it is mentioned in the Java Memory Model that: When a thread exits a synchronized block as part of releasing the associated monitor, the JMM requires that the local processor cache be flushed to main memory. Similarly, as part of acquiring the monitor when entering a synchronized block, local caches are invalidated so that subsequent reads will go directly to main memory and not the local cache.
so why in that code I must declare instance as volatile since when the second thread enters the synch block will go directly to main memory ??
public final class MySingleton {
private static MySingleton instance = null;
private MySingleton() { }
public static MySingleton getInstance() {
if (instance == null) {
synchronized (MySingleton.class) {
if (instance == null) {
instance = new MySingleton();
}
}
}
return instance;
}
}
I mean when another thread enters synch block and make the second check it is supposed to update from main memory as mentioned.
The race condition is this:
Thread A sees
instance == NULLand is running this codeinstance = new MySingleton();. The write toinstanceis visible but the writes intoMySingletonare not yet.Thread B sees
instance != NULLand starts working on instance.Thread B is now working on an object whose construction it cannot see.
Making
instancevolatile solves the problem as the JDK memory specification, as of JDK5, guarantees that writes to non-volatile objects will not be seen out of order with respect to a write to a volatile object. So any thread that seesinstance != NULLmust see the instance itself.