I am taking a book to do some mock test, I have found this question:
import java.util.concurrent.atomic.AtomicInteger;
class AtomicVariableTest {
private static AtomicInteger counter = new AtomicInteger(0);
static class Decrementer extends Thread {
public void run() {
counter.decrementAndGet(); // #1
}
}
static class Incrementer extends Thread {
public void run() {
counter.incrementAndGet(); // #2
}
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Incrementer().start();
new Decrementer().start();
}
System.out.println(counter);
}
}
The answer:
This program will always print 0.
But I think there is no guarantee that the threads will have completed when it prints the counter value.
I mean, most of the time it will return 0, but if you are strict with the theory there is no guarantee of this.
Am I correct?
There is guaranteed. And there is not guaranteed. There is no middle ground.
In this case there is no guarantee that the result is always zero. This is because the threads are not joined - and might never even have actually ran before the print!
For example, among other permutations, the sequence this code could have executed is:
counter.decrementAndGet(); // #1
System.out.println(counter); // Main thread
counter.incrementAndGet(); // #2
// (and so on, at some arbitrary point after the print)
Avoiding such undesired interleaving/execution is handled in Java (as per the JLS) under happens-before relationships.
If the threads were joined (to the thread with the print) then a happens-before would have been established - in this case that would mean that the threads started and finished running - and the result would be guarantee to be zero.
public static void main(String[] args) {
final List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 5; i++) {
final new Incrementer i = new Incrementer();
threads.add(i);
i.start();
final new Decrementer d = new Decrementer();
threads.add(d);
d.start();
}
for (final Thread t : threads) { t.join(); }
System.out.println(counter);
}
See one of the many duplicates: Wait until child threads completed : Java
And this is why you use the ExecutorService
or ExecutorCompletionService
and never deal with thread management manually because it is extremely error prone otherwise.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With