update memory before synchronization?
-
13-12-2019 - |
Question
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.
Solution
The race condition is this:
Thread A sees
instance == NULL
and is running this codeinstance = new MySingleton();
. The write toinstance
is visible but the writes intoMySingleton
are not yet.Thread B sees
instance != NULL
and starts working on instance.Thread B is now working on an object whose construction it cannot see.
Making instance
volatile 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 sees instance != NULL
must see the instance itself.
OTHER TIPS
You have to declare it volatile otherwise there is no guarantee that two calls to getInstance() will return the same instance.
There is no guarantee that main memory will be accessed, only a cache-consistent value. i.e. all threads will see the same value.
BTW: You know of course its far more complex than needed. All you need is
public enum MySingleton {
INSTANCE;
}
does much the same thing.