Recently in a conference talk the following was used as an example to demonstrate the Java memory model in a multithreaded environment.
public class A {
public static boolean done;
public static void main(String[] args) throws InterruptedException {
done = false;
new Thread(new Runnable(){
public void run() {
System.out.println("running...");
int count = 0;
while (!done) {
count++;
}
System.out.println("Exiting thread");
}
}).start();
System.out.println("in main...");
Thread.sleep(2000);
System.out.println("setting done to true");
done = true;
}
}
I understand that the new thread created in above code will never exit because of done
variable being cached in Thread's local cache. And a proper solution will be to make the done
variable volatile.
But if inside the while loop, we call Thread.sleep()
as follows
while (!done) {
count++;
try {Thread.sleep(0);} catch(Exception e){}
}
then the Thread successfully exits.
My understanding is that because of sleep(0)
a context switch will occur that will invalidate the cache entries, so each time the updated value of done
is retrieved. Is my understanding correct? Also is this behaviour dependent on the number of cores of the machine?
The Java memory model describes how threads in the Java programming language interact through memory. Together with the description of single-threaded execution of code, the memory model provides the semantics of the Java programming language.
JVM Memory Structure. JVM creates various run time data areas in a heap. These areas are used during the program execution. The memory areas are destroyed when JVM exits, whereas the data areas are destroyed when the thread exits.
The memory model stipulates that changes to the values of shared variables only need to be made visible to other threads when such a synchronization barrier is reached. Moreover, the entire notion of a race condition is defined over the order of operations with respect to these memory barriers.
The following are key memory segments inside a JVM: Program Counter (PC) Register. Method Area. Heap.
Java Language Specification clearly states that Thread::sleep
does not have any happens-before semantics (and those are the only one you want to reason with):
... Thread.sleep nor Thread.yield have any synchronization semantics...
As such whatever output you "happen" to see using it, are not guaranteed by the specification. The only guarantees you have is when done is volatile
, again, because the JLS gives you such guarantees.
Your reasoning about a correctly synchronized program must be backed against happens-before, context switch, caches, etc. are irrelevant.
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