SingletonFactory and safe publication
Hi:
I am reading this article(http://shipilev.net/blog/2014/safe-public-constru=
ction/). It says the following code is GOOD:
public class SafeDCLFactory {
private volatile Singleton instance;
public Singleton get() {
if (instance == null) { // check 1
synchronized(this) {
if (instance == null) { // check 2
instance = new Singleton();
}
}
}
return instance;
}
}
I feel disagree, by learning from this article(http://en.wikipedia.org/wiki=
/Double-checked_locking).
If without 'volatile', the code above has two problems, not one problem: 1)=
other threads may not see the content of 'instance' which is initiated by c=
onstructing thread; 2)It is possible thread A is in the middle of construct=
ing the object, so the reference 'instance' is not null, but what it refere=
nces maybe an partially initiated object, so thread B may get this partiall=
y initiated object, causing crash later on.
Adding 'volatile' only solves the first problem, not the second. According =
to the second article above, the CORRECT way is:
class Foo {
private volatile Helper helper;
public Helper getHelper() {
Helper result = helper;
if (result == null) { //1st check
synchronized(this) {
result = helper;
if (result == null) { //2nd check
helper = result = new Helper();
}
}
}
return result;
}
// other functions and members...
}
The article does not explain well why the second problem is prevented. But =
I think when the constructing thread is doing:
helper = result = new Helper();
if in the middle of constructing(the worst case), 'result' is referencing i=
t, but 'helper' is still null. Other threads will get TRUE for 1st check an=
d go into the block[first if(result==null) block], after getting the lo=
ck(the constructing thread must have finished and released the lock), now '=
result' becomes the reference pointing to a good, solid object. 2nd check w=
ill fail(and avoids constructing).
I would like to ask help to understand why the following code is GOOD. The =
code uses 'final', instead of 'volatile':
public class FinalWrapper<T> {
public final T value;
public FinalWrapper(T value) {
this.value = value;
}
}
public class Foo {
private FinalWrapper<Helper> helperWrapper;
public Helper getHelper() {
FinalWrapper<Helper> wrapper = helperWrapper;
if (wrapper == null) { //1st check
synchronized(this) {
if (helperWrapper == null) { //2nd check
helperWrapper = new FinalWrapper<Helper>(new Helper());
}
wrapper = helperWrapper;
}
}
return wrapper.value;
}
}
Thank you.