带有两个同步块的DCL坏了吗?

时间:2015-11-20 07:43:50

标签: java multithreading synchronized double-checked-locking

我无法理解A fix that doesn't work下面的代码段。 (我确实阅读了同一页面上的解释)。

如果我们有2个同步块,这个DCL版本是如何破坏的?或者它不适用于Java5之后?

// (Still) Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo { 
  private Helper helper = null;
  public Helper getHelper() {
    if (helper == null) {
      Helper h;
      synchronized(this) {
        h = helper;
        if (h == null) 
            synchronized (this) {
              h = new Helper();
            } // release inner synchronization lock
        helper = h;
        } 
      }    
    return helper;
    }
  // other functions and members...
  }

1 个答案:

答案 0 :(得分:3)

不能保证将helper视为非null的线程能够看到new Helper();所做的所有写操作。所以你可以访问单身的腐败版本。您需要在线程中将helper视为非null,以确保在h = new Helper(); 完成后看到。观察对非易失性变量的更改并不能建立这样的关系,并且这就是所有线程所做的。

过度简化,Java的内存可见性模型的工作方式是两个线程各自做一些事情,建立一个"发生在" /"发生在"两个线程完成的两个操作之间的关系。这可以包括同步块内的操作或访问volatile变量。

但是使用上面的代码,线程可以观察到helper不是null,然后继续访问由new Helper()创建的对象。它不必访问volatile变量,也不必输入同步块。所以没有任何东西可以建立所需的"发生在"关系以确保它看到new Helper()所做的任何更改。