I have seen some similar questions,but I still have some confusions.
code is here:
private volatile static DoubleCheckSingleton instance;
private DoubleCheckSingleton() {}
public static DoubleCheckSingleton getInstance(){
if(instance==null){ //first
synchronized (DoubleCheckSingleton.class){
if(instance==null){ // second
instance=new DoubleCheckSingleton();
}
}
}
return instance;
}
In this question Why is volatile used in double checked locking, it says that without a volatile
keyword, a thread may assign the instance variable before the constructor finishes, so another thread may see a half-constructed object, which can cause serious problem.
But I don't understand how volatile can solve the problem. Volatile
is used to ensure visibility, so when thread A assign a half-constructed object to instance variable, the other thread can immediately see the change, which makes the situation worse.
How does volatile
solve the problem, somebody please explain to me. Thanks!
a thread may assign the instance variable before the constuctor finishes
That's not actually true. The assignment is right there in the code example:
instance=new DoubleCheckSingleton()
Obviously, the thread that performs that assignment can not possibly do the assignment before the constructor call has returned.
The problem is, when two different threads are running on two different processors without any synchronization, they will not necessarily agree upon the order in which assignments happen. So, even though thread A assigned the fields of the new object (inside the new DoubleCheckSingleton()
call) before it assigned instance
, thread B potentially could see those assignments out-of-order. Thread B could see the assignment to instance
before it sees some of the other things that new DobuleCheckSingleton()
did.
Declaring instance
to be volatile
synchronizes the threads. volatile
guarantees that everything thread A did before it assigned a volatile
variable will become visible to thread B when thread B fetches the value of the volatile
variable.