4

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?

Blorgbeard
  • 101,031
  • 48
  • 228
  • 272
Daniel Hernández
  • 4,078
  • 6
  • 27
  • 38
  • Sure, I could try thousands of times without lucky ! I just want to know if you are agree – Daniel Hernández Sep 09 '15 at 02:49
  • I'm voting to close this question as off-topic because you are not actually asking a question with a specific answer, you are asking for **discussion**. This is **NOT** a forum and discussions is extremely **off-topic**. –  Sep 09 '15 at 02:53
  • 3
    This question is not asking for discussion, it's asking a specific question about how a specific code-snippet works. – Blorgbeard Sep 09 '15 at 02:56
  • I could change the question to "what is the correct answer?" ritght ... in fact, I think that question has only one answer – Daniel Hernández Sep 09 '15 at 02:56
  • this is a duplicate of http://stackoverflow.com/questions/9939076/wait-until-child-threads-completed-java –  Sep 09 '15 at 03:12

1 Answers1

10

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.

Community
  • 1
  • 1
user2864740
  • 60,010
  • 15
  • 145
  • 220
  • even though it is correct now it is worded extremely unclear you need to put a code example to clarify where the `.join()` would be to make it as described. –  Sep 09 '15 at 03:00
  • I fixed it, you can all delete your comments you made while I was looking it up, it did not look right to me either. –  Sep 09 '15 at 03:11