What for volatile stuff in Double check? [closed]
Lets look at classical double check
class Foo {
private volatile Foo singleton = null;
public Foo getFooSingleton() {
if (singleton == null) {
synchronized(this) {
if (singleton == null)
singleton = new Foo();
}
}
return singleton;
}
}
Volatile modifire guaranties that value of "singleton" variable will be seen correctly in 开发者_运维技巧all threads. But really do I need this in current example? I think no. So - that's how I see this program runs in the worst way - when changes made by one thread are not seen by other.
- thread one enteres synchronized section and creates singleton
- thread two enteres synchronized, synchronize its current stack values (now he sees
singleton != null
), makes second check and exits synchronized section.
So. Everything works even without volatile declaration, and even better =)
Yes, volatile
is needed here.
The point is that without memory barrier between creation of Foo
(which includes creation of the object and execution of its constructor) and storing a reference to it in the singleton
field other threads can observe these actions happening in arbitrary order. In particular, during the first check thread 2 can observe a reference pointing to the partically constructed object. Note that synchronized
block can't help here, since thread 2 sees singleton != null
and doesn't enter it at all.
Use of volatile
ensures placing of the appropriate memory barrier (since Java 5; in previous versions double check idiom couldn't be implemented at all).
The problem with DCL in Java is not the cost of extra synchronization. The real problem is that without volatile
modifier (and before Java 5) your threads can see improperly constructed singleton
object.
Just to be clear. Write to the singleton
reference and writes to singleton
's fields being sequential in singlethreaded program may be out of order in multithreaded.
精彩评论