为什么用Java检查双重检查锁定?

据说,除了long或double字段外,字段赋值总是primefaces的。

但是,当我读到为什么双重检查锁定被破坏的解释时,它说问题在于赋值操作:

// Broken multithreaded version // "Double-Checked Locking" idiom class Foo { private Helper helper = null; public Helper getHelper() { if (helper == null) { synchronized(this) { if (helper == null) { helper = new Helper(); } } } return helper; } // other functions and members... } 
  1. 线程A注意到该值未初始化,因此它获得锁定并开始初始化该值。
  2. 由于某些编程语言的语义,允许编译器生成的代码在A完成初始化之前更新共享变量以指向部分构造的对象。
  3. 线程B注意到共享变量已初始化(或显示),并返回其值。 因为线程B认为该值已经初始化,所以它不会获得锁定。 如果B在B看到A完成的所有初始化之前使用该对象(因为A尚未完成初始化或者因为对象中的某些初始化值尚未渗透到内存B使用(缓存一致性)) ,该程序可能会崩溃。
    (来自http://en.wikipedia.org/wiki/Double-checked_locking )。

什么时候可能? 是否有可能在64位JVM分配操作上不是primefaces的? 如果不是那么“双重检查锁定”是否真的被打破了?

问题不在于primefaces性,而在于它的排序。 只要不违反发生之前的事件 ,JVM就可以重新排序指令以提高性能。 因此,运行时理论上可以在执行类Helper的构造函数的所有指令之前调度更新helper程序的指令。

引用的赋值是primefaces的,但构造不是! 因此,如解释中所述,假设线程B想要在线程A完全构造它之前使用单例,它不能创建新实例,因为引用不是null,因此它只返回部分构造的对象。

如果您不确保在另一个线程加载该共享引用之前发布共享引用,则可以通过对其字段的写入来重新排序对新对象的引用的写入。 在这种情况下,另一个线程可以看到对象引用的最新值,但是对象的某些或全部状态的过期值 – 部分构造的对象。 – Brian Goetz:Java Concurrency in Practice

由于初始检查null未同步,因此没有发布,并且可以进行此重新排序。

在构造函数中构造Helper的实例可能需要几个赋值,并且语义允许它们相对于赋值helper = new Helper()重新排序。

因此,可以为字段helper分配对未进行所有分配的对象的引用,以使其未完全初始化。

在java中双重检查锁定有各种各样的问题:

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

阅读这篇文章: http : //www.javaworld.com/jw-02-2001/jw-0209-double.html即使你不理解所有细节(像我一样),只要相信这个好方法不起作用。

对不起,这可能与这个问题有点无关,我只是好奇。 在这种情况下,在分配之前获取锁定和/或返回值是不是更好? 喜欢:

 private Lock mLock = new ReentrantLock(); private Helper mHelper = null; private Helper getHelper() { mLock.lock(); try { if (mHelper == null) { mHelper = new Helper(); } return mHelper; } finally { mLock.unlock(); } } 

或者使用双重检查锁定是否有任何优势?

 /*Then the following should work. Remember: getHelper() is usually called many times, it is BAD to call synchronized() every time for such a trivial thing! */ class Foo { private Helper helper = null; private Boolean isHelperInstantiated; public Helper getHelper() { if (!isHelperInstantiated) { synchronized(this) { if (helper == null) { helper = new Helper(); isHelperInstantiated = true; } } } return helper; } // other functions and members... }