Lets save I have this code which exhibits stale cache reads by a thread, which prevent it from exiting its while loop.
class MyRunnable implements Runnable {
boolean keepGoing = true; // volatile fixes visibility
@Override public void run() {
while ( keepGoing ) {
// synchronized (this) { } // fixes visibility
// Thread.yield(); // fixes visibility
System.out.println(); // fixes visibility
}
}
}
class Example {
public static void main(String[] args) throws InterruptedException{
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
Thread.sleep(100);
myRunnable.keepGoing = false;
}
}
I believe the Java Memory Model guarantees that all writes to a volatile variable synchronize with all subsequent reads from any thread, so that solves the problem.
If my understanding is correct the code generated by a synchronized block also flushes out all pending reads and writes, which serves as a kind of "memory barrier" and fixes the issue.
From practice I've seen that inserting yield
and println
also makes the variable change visible to the thread and it exits correctly. My question is:
Is yield/println/io serving as a memory barrier guaranteed in some way by the JMM or is it a lucky side effect that cannot be guaranteed to work?
Edit: At least some of the assumptions I made in the phrasing of this question were wrong, for example the one concerning synchronized blocks. I encourage readers of the question to read the corrections in the answers posted below.