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.
thanks
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.
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.)
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