0

Why doesn't variable named 'count' finally equal to 20000?

public class Main {
private Integer count = 0;

public void increment() {
    synchronized (count) {
        count++;
    }
}

public static void main(String[] args) {
    Main app = new Main();
    app.doWork();
}

public void doWork() {

    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            for (int i=0; i<10000; i++) {
                increment();
            }
        }
    });

    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            for (int i=0; i<10000; i++) {
                increment();
            }
        }
    });

    t1.start();
    t2.start();
    System.out.println(count);
}

It seems that thread loses the variable but when does it happen? The same happens in a case of using AtomicInteger too.

P.S. could you please recommend a good course with exercises for learning multithreading in Java?)

2 Answers2

3

Because start creates a new thread, and when you print the count you aren't sure the thread execution is finished.

t1.start();
t2.start();

System.out.println(count); // Here you don't know if t1 and t2 ended their execution

Join threads to wait for them to complete the task:

t1.start();
t2.start();

t1.join(); // wait for t1 to finish
t2.join(); // wait for t2 to finish

System.out.println(count); // 20000

Note: You'll have to handle InterruptedException on join calls.

BackSlash
  • 21,927
  • 22
  • 96
  • 136
  • Thank you for an answer but to my mind, @bowmore is right in this particular situation –  Nov 29 '17 at 12:28
  • @PavelPavel It isn't. Your question was "Why doesn't variable named 'count' finally equal to 20000?" and the answer is "because you aren't waiting for the threads to terminate". bowmore, to answer this particular question, told you to read my answer. – BackSlash Nov 29 '17 at 12:35
  • Yes. I've made 2 mistakes –  Nov 29 '17 at 13:01
2

You synchronize on count. But your code changes count. Different threads synchronizing on different objects don't guarantee atomicity.

Use a separate final monitor object to synchronize on.

See also @BackSlash 's answer for making sure you print the correct end result.

Edit

His answer comes down to : if you print the result without waiting for the threads to finish on your main thread you'll see some intermediate result, or possibly even 0.

So you need to call join(), which blocks until the thread finishes, on both threads before printing the end result.

bowmore
  • 10,842
  • 1
  • 35
  • 43