非易失性领域的出版与阅读

2024-05-14

public class Factory {
    private Singleton instance;
    public Singleton getInstance() {
        Singleton res = instance;
        if (res == null) {
            synchronized (this) {
                res = instance;
                if (res == null) {
                    res = new Singleton();
                    instance = res;
                }
            }
        }
        return res;
    }
}

这几乎是线程安全的正确实现Singleton。我看到的唯一问题是:

The thread #1即初始化instance字段可以在完全初始化之前发布。现在,第二个线程可以读取instance处于不一致的状态。

但是,对于我的眼睛来说only问题在这里。难道只是这里有问题吗? (我们可以使instance易挥发的)。


Shipilev 在中解释了您的示例Java 中的安全发布和安全初始化 https://shipilev.net/blog/2014/safe-public-construction/。我强烈建议阅读整篇文章,但总结一下看看UnsafeLocalDCLFactory那里的部分:

public class UnsafeLocalDCLFactory implements Factory {
  private Singleton instance; // deliberately non-volatile

  @Override
  public Singleton getInstance() {
    Singleton res = instance;
    if (res == null) {
      synchronized (this) {
        res = instance;
        if (res == null) {
           res = new Singleton();
           instance = res;
        }
      }
    }
    return res;
  }
}

以上存在以下问题:

这里引入局部变量是一个正确性修复,但只是部分的:在发布 Singleton 实例和读取其任何字段之间仍然没有发生之前。我们只是保护自己不返回“null”而不是 Singleton 实例。同样的技巧也可以被视为 SafeDCLFactory 的性能优化,即只执行一次易失性读取,产生:

Shipilev 建议按如下方式修复,通过标记instance易挥发的:

public class SafeLocalDCLFactory implements Factory {
  private volatile Singleton instance;

  @Override
  public Singleton getInstance() {
    Singleton res = instance;
    if (res == null) {
      synchronized (this) {
        res = instance;
        if (res == null) {
          res = new Singleton();
          instance = res;
        }
      }
    }
    return res;
  }
}

这个例子没有其他问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

非易失性领域的出版与阅读 的相关文章