双重检查锁定既没有volatile也没有局部变量

时间:2016-05-15 15:07:56

标签: java multithreading double-checked-locking

在解除此之前,可以实现双重检查锁定而不用 volatile,见下文。我建议对此进行修改,摆脱局部变量。

以下是来自Shipilev的双重检查锁定的正确实现:

public class FinalWrapperFactory {
  private FinalWrapper wrapper;

  public Singleton get() {
    FinalWrapper w = wrapper;
    if (w == null) { // check 1
      synchronized(this) {
        w = wrapper;
        if (w == null) { // check2
          w = new FinalWrapper(new Singleton());
          wrapper = w;
        }
      }
    }
    return w.instance;
  }

  private static class FinalWrapper {
    public final Singleton instance;
    public FinalWrapper(Singleton instance) {
      this.instance = instance;
    }
  }
}

我想知道是否有可能摆脱局部变量w

public class FinalWrapperFactory {
  private FinalWrapper wrapper; //same as example above

  public Singleton get() {
    if (wrapper == null) { // read 1
      synchronized(this) {
        if (wrapper == null) { // read 2
          wrapper = new FinalWrapper(new Singleton());
          return wrapper.instance; // read 3
        } else {
          return wrapper.instance; // read 4 
        }
      }
    } else {
      return wrapper.instance; // read 5 (last read). Can this be reordered?
    }
  }
}

17.4.8. Executions and Causality RequirementsJLS 8中写道:

  

非正式地,如果我们知道,我们允许提前采取行动   可以在不假设发生某些数据竞争的情况下发生此操作。

这里的一个重要问题是,如果最后一次读取(读取5)可以重新排序,那么我们可能会在读取1中看到非空的包装器,并且在上次读取时仍然看到空值。不应该在线程第一次调用get()时发生这种情况,因为最后一次读取的唯一方法是因为数据竞争而JMM会禁止重新排序。

在随后的get()调用中,将允许重新排序,但它应该无关紧要,因为无论如何都应该可以看到包装器。

0 个答案:

没有答案
相关问题