I read that even 'double checked locking' is not thread safe. Thread one can get out of synchronized block before JVM assign instance to singleton reference, in that case, thread two will enter into synchronized block and pass the if condition (as singleton is not initialized) and create another instance.
If that can happen then *anything* can happen. JVM is supposed to execute code sequentially until it's specified NOT to do so.
I am totally lost now. [ June 06, 2007: Message edited by: ankur rathi ]
JVM is supposed to execute code sequentially until it's specified NOT to do so.
Actually the JVM is allowed a certain amount of freedom to mess about with that while optimizing. And it can keep data in temporary memory (I imagine registers in hardware) a while before it puts it back in the real variable.
When you read my theoretical proofs, you will think I am very clever, thus enabling me to raise my rates next time you ask for help. At the same time, the problems described only happen on a fast multi-processor machine, and it is unlikely that you have one of those standing at home, so you cannot even contradict me.
I have tried to gather some evidence that with the current JVM implementations the problem can occur. I have written test code and executed it on a friend's multi-processor. I was not successful in proving my assertions. I have spoken to a number of authors who have written about this problem, and they also do not have firm evidence that this occurs in the real world. I therefore offer no proof or even claim that what I wrote about in this newsletter is true.
That is really all I have to say about the matter. Avoid the double-checked locking to avoid synchronization. In JDK 1.5 they are tidying up the memory model thus showing more clearly that DCL is broken. In the meantime, try not to be too clever ;-)
[ June 06, 2007: Message edited by: Stan James ]
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
It is educational to read all about this stuff, but the quick thing to take away is: -
Never try to do something "clever" to avoid synchronisation - it probably won't work and, even if it does, it won't save a worthwhile amount of time.
Use synchronisation in a simple, obvious fashion, to control threads' access to shared data, and no-one will get hurt.
Betty Rubble? Well, I would go with Betty... but I'd be thinking of Wilma.
Joined: Jan 29, 2003
Yup. Keep it simple. At the top of that complex Java Specialists newsletter, he recommends my favorite form:
About as simple as you could want with no synchronization. And even a synchronized getInstance() that checks for null is not going to block other threads long enough to worry about, especially since Sun warns us not to use Java in apps that are all that sensitive to the occasional delay.
And even a synchronized getInstance() that checks for null is not going to block other threads long enough to worry about, especially since Sun warns us not to use Java in apps that are all that sensitive to the occasional delay.
I agree. You should do that when you dont have the choice of eager instantiation. But DCL is fixed with Java 5 and above. I would still rather use eager instantiation or a synchronized getInstance() to avoid confusion.
[John Meyers]: But DCL is fixed with Java 5 and above.
That's only if you make the instance field volatile. The original DCL did not use volatile, and is still broken. And using volatile with DCL wasn't guaranteed to work correctly prior to JDK 5.
I agree that using eager instantiation is simpler, and thus, often preferable. But there are some cases where the initialization is expensive, and may not even be needed for some programs, so lazy instantiation can make sense. In that case, this works:
Or at least, it works as well as Singleton ever works. Meaning if you've got multiple classloaders, or a distributed computing environment, you probably need to try something else.