When I was reading Wikipedias’s article about Double Checked Locking idiom, I’m confused about its implementation:
public class FinalWrapper<T> {
public final T value;
public FinalWrapper(T value) {
this.value = value;
}
}
public class Foo {
private FinalWrapper<Helper> helperWrapper = null;
public Helper getHelper() {
FinalWrapper<Helper> wrapper = helperWrapper;
if (wrapper == null) {
synchronized(this) {
if (helperWrapper == null) {
helperWrapper = new FinalWrapper<Helper>(new Helper());
}
wrapper = helperWrapper;
}
}
return wrapper.value;
}
}
I simply don’t understand why we need to create wrapper. Isn’t this enough ?
if (helperWrapper == null) {
synchronized(this) {
if (helperWrapper == null) {
helperWrapper = new FinalWrapper<Helper>(new Helper());
}
}
}
Is it because using wrapper can speed up initialization because wrapper is stored on stack and helperWrapper is stored in heap?
No this isn’t enough.
Above, first check for
helperWrapper == nullis not thread safe. It may return false (seeing non-null instance) for some thread “too early”, pointing to not fully constructed helperWrapper object.The very Wikipedia article you refer to, explains this issue step-by-step:
Note semantics of some programming languages mentioned above is exactly the semantic of Java as of version 1.5 and higher. Java Memory Model (JSR-133) explicitly allows for such behavior – search the web for more details on that if you’re interested.
No, above isn’t the reason.
The reason is thread safety. Again, semantic of Java 1.5 and higher (as defined in Java Memory Model) guarantees that any thread will be able to access only properly initialized Helper instance from wrapper due to the fact that it is a final field initialized in constructor – see JLS 17.5 Final Field Semantics.