First of all:
Again when using the synchronized keyword, the code reorder never happens as per the JMM specification.
The above statement is not fully accurate. The JMM defined the happens-before relationship.
The JLS only defines the program order and happens-before order. See 17.4.5. Happens-before Order.
It has effects on the reordering of instructions. For example,
int x = 1;
synch(obj) {
y = 2;
}
int z = 3;
Now for the above piece of code, the below types of reordering are possible.
synch(obj) {
int x = 1;
y = 2;
int z = 3;
}
The above is a valid reordering.
See Roach Motels and The Java Memory Model.
synch(obj) {
int z = 3;
y = 2;
int x = 1;
}
The above is also a valid reordering.
What is not possible is that y=2 will only be executed after the lock has been acquired and before the lock is released this is what guaranteed given by JMM. Also to see the correct effects from another thread, we need to access y inside the synchronized block only.
Now I come to DCL.
See the code of DCL.
if (singleton == null)
synch(obj) {
if(singleton == null) {
singleton == new Singleton()
}
}
return singleton;
Now the problem in the above approach is:
singleton = new Singleton()
is not a single instruction. But a set of instructions. It is quite possible that a singleton reference is assigned an object reference first, before fully initializing the constructor.
So if 1 happens then it's quite possible the other thread reads a singleton reference as a non null and thus is seeing a partially constructed object.
The above effects can be controlled by making a singleton as volatile which also establishes happens-before guarantees and visibility.