Java中的双重检查锁定中的volatile

Iva*_*nko 4 java multithreading

据我所知,这是Java中双重检查锁定模式的正确实现(自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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否缺少volatile是一个严重的错误或只是一个轻微的不完美与可能的性能缺陷假设_barInstance只通过访问getBar.

我的想法如下:synchronized介绍发生在之前的关系.初始化的线程_barInstance将其值写入主存储器,离开同步块.因此,_barInstance即使不是,也不会进行双重初始化volatile:其他线程null在其本地副本中有_barInstance(true在第一次检查中获取),但在进入同步后必须在第二次检查中从主存储器中读取新值阻止(获取false并不重新初始化).所以唯一的问题是每个线程的锁定获取过多.

据我所知,它在CLR中是正确的,我相信它在JVM中也是正确的.我对吗?

谢谢.

小智 7

在以下情况下,不使用volatile可能会导致错误:

  • 线程1进入getBar()并发现_barInstance是null
  • 线程1尝试创建Bar对象并更新对象的引用_barInstance.由于某些编译器优化,这些操作可能不按顺序进行.
  • 同时,线程2进入getBar()并看到非空,_barInstance但可能会在_barInstance对象的成员字段中看到默认值.它基本上看到了部分构造的对象,但引用不是null.

的volatile改性剂将禁止写入或读取可变的_barInstance相对于任何先前的读或写.因此,它将确保线程2不会看到部分构造的对象.

有关详细信息,请访问:http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html