As I understand, this is a correct implementation of the double-checked locking pattern in Java (since Java 5):
class Foo {
private volatile Bar _barInstance;
public Bar getBar() {
if (_barInstance == null) {
synchronized(this) { // or synchronized(someLock)
if (_barInstance == null) {
Bar newInstance = new Bar();
// possible additional initialization
_barInstance = newInstance;
}
}
}
return _barInstance;
}
}
I wonder if absence of volatile
is a serious error or just a slight imperfection with possible performance drawback assuming _barInstance
accessed only through getBar
.
My idea is the following: synchronized
introduces happens-before relation. The thread that initializes _barInstance
writes its value to the main memory leaving the synchronized block. So there will be no double initialization of _barInstance
even when it isn't volatile
: other threads have null
in theirs local copies of _barInstance
(get true
in the first check), but have to read the new value from the main memory in the second check after entering the synchronized block (get false
and do no re-initialization). So the only problem is an excessive one-per-thread lock acquisition.
As I understand, it's correct in CLR and I believe it's also correct in JVM. Am I right?
Thank you.