【问题标题】:Use of volatile in singleton double null check implementation in java在 java 中的单例双空检查实现中使用 volatile
【发布时间】:2017-01-28 05:19:47
【问题描述】:

我想知道在 Singleton 的双空检查实现中将 Instance 变量设置为 volatile 有什么用。因为根据我的理解,同步块提供隐式发生在之前。没有两个线程可以同时访问该同步块,并且在退出同步块时,线程将其所有本地缓存​​数据写入主内存。 我搜索了很多,但我仍然对这个实现有疑问。请说明正确使用方法。

private volatile Singleton INSTANCE; 
public Singleton get() { 
    if (INSTANCE == null) { 
        synchronized (this) { 
            if (INSTANCE == null) { 
                INSTANCE = new Singleton(); 
            } 
        } 
    } 
    return INSTANCE; 
}

在上面的双重检查代码中。如果我不让我的实例变得易变,可能会出现什么问题。因为当第一个线程进入同步块时,没有其他线程可以访问该块。当第一个线程离开该块时。对象将被创建,由于发生在属性之前,实例的最新值将被写入主内存。那么为什么 volatile 在这种情况下很重要呢?

这是类似问题的链接 (Is there any need to add volatile keyword to guarantee thread-safe singleton class in java?)。但答案不是很清楚。 我认为在上述给定的场景中,任何类型的 JVM 优化都不会导致同步块之前发生中断

【问题讨论】:

  • 向我们展示您正在谈论的代码,并在您谈论之前准确地向我们展示发生了什么。那我们就可以解释了。
  • (这可能是重复的,但如果没有更多细节,很难选择最好的副本。)
  • 请将其放入问题中。
  • 这是28034564的副本

标签: java multithreading singleton volatile


【解决方案1】:

volatile 在这里很重要,因为 JVM 在字节码级别的内部结构。声明

INSTANCE = new Singleton()

实际上是在字节码级别:

1. INSTANCE = create Singleton object
2. call constructor of INSTANCE

如果 INSTANCE 是volatile,JVM 保证从其他线程的角度来看 1+2 作为原子操作执行,例如通过在将实例存储在字段中之前将其存储在堆栈中。如果它不是volatile,则其他线程可能已经看到在调用构造函数之前对Singleton 的引用。因此这些线程可能会看到一个不完整的对象。

【讨论】:

    【解决方案2】:

    因为根据我的理解,同步块提供隐式发生在之前。没有两个线程可以同时访问该同步块,同时退出同步块

    如果你有一个简单的惰性单例实现是正确的。每次对变量的访问都要经过同步块。

    private Singleton INSTANCE;
    
    public static synchronized Singleton getInstance() {
      if (INSTANCE == null) {
        INSTANCE = new Singleton();
      }
      return INSTANCE;
    }
    

    但是一旦你有一个安全的双重检查惰性实现,并不是每个代码路径都通过同步块。对该方法的第二次调用将从本地字段中读取变量,而无需输入 synchronized 块,并且 INSTANCE 必须是 volatile。

    private volatile Singleton INSTANCE;
    
    public Singleton get() {
      if (INSTANCE == null) {
        synchronized (this) {
          if (INSTANCE == null) {
            INSTANCE = new Singleton();
          }
        }
      }
      return INSTANCE;
    }
    

    您可以在this article 中阅读有关安全发布的更多信息。

    【讨论】:

    • 感谢您澄清 volatile 仅适用于双重检查锁定单例模式,并给出“第一次检查 INSTANCE 变量检查 null 而不进入同步块”的正当理由。
    猜你喜欢
    • 1970-01-01
    • 2020-03-31
    • 2016-11-26
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多