William
William

Reputation: 1895

Why does Java not see the updated value from another thread?

Please look at this code(taken from Effective Java book)

import java.util.concurrent.TimeUnit;


public class Main {
private static boolean stopReq;
public static void main(String[] args) throws InterruptedException {
    
    
    Thread bgw = new Thread(new Runnable()
    {
        public void run(){
        
        int i = 0;
        while(!stopReq){ i++;}
        }
        });
    bgw.start();
    TimeUnit.SECONDS.sleep(1);
    stopReq = true;

}

}

Why does the bgw thread get stuck in an infinite loop? Is it caching it's own copy of stopReq when it reached the loop? So it never sees the updated value from the other thread?

I understand the solution to this problem would be synchronizing or a volatile variable, but I am curious to why this current implementation doesn't work.

Upvotes: 11

Views: 4209

Answers (5)

Mak
Mak

Reputation: 616

To be very specific about your query, to take full advantage of the performance of modern multiprocessor hardware, in absence of synchronization, JVMs allowed to permit compiler to re-order operations and cache values in registers and in processor specific caches. As main thread writes to stopReq without synchronization so because of reordering and caching the BTW thread might never see the written value and loop forever.

When you use synchronization or volatile they guarantee VISIBILITY and force compiler not to cache and flush changes to main memory.

Upvotes: 0

JB-
JB-

Reputation: 2670

You should read more about Java Memory Model to better understand all the implications.

Shortly, the stopReq variable not being volatile or included in a synchronized block gives the VM freedom to use an optimized local storage (eg. registers etc) which is not guaranteed to propagate changes immediately across the threads.

When you declare the variable as volatile the VM will make sure that after each variable write a "memory write barrier" is inserted which will force all the local changes to be spilled to the real memory location thus making it visible to all the other threads (the same barrier is placed at the end of a synchronized block eg.)

Upvotes: 1

Anedar
Anedar

Reputation: 4265

I tested this out, and no, the variables are the same. The example also compiles for me.

The error is here:

Your while loop goes on, as long as !stopReq is true, that means stopReq is false. And after 1 sec you set stopReq to false - this changes nothing. If you set it to true, !stopReq will become false and your loop will end.

Upvotes: 0

Rahul
Rahul

Reputation: 3509

Make stopReq to true, then it will be stopped. You are again setting the stopReq to false, due to that while loop condition is true always and it is in infinite loop.

Upvotes: 0

Jean Logeart
Jean Logeart

Reputation: 53819

Your explanation is right.

The compiler detects than stopReq is never modified in the loop and since it is not volatile, optimizes the while(!stopReq) instruction to while(true).

Even though the value changes later, the thread does not even read it any more.

Upvotes: 16

Related Questions