为什么没有 volatile 的 DCL 对原语有效?

Why DCL without volatile is valid for primitives?

免责声明:我没有在实际生产代码中使用 DCL - 我只是出于学术兴趣。

我读过以下著名文章:The "Double-Checked Locking is Broken" Declaration

问题申明(我的设想):

// Correct multithreaded version
class Foo { 
  private Helper helper = null;
  public synchronized Helper getHelper() {
    if (helper == null) 
        helper = new Helper();
    return helper;
    }
  // other functions and members...
  }

假设 thread_1 执行行 helper = new Helper(); 另一个 Thread(thread_2) might 看到 helper link 不为 null 但尚未初始化。发生这种情况是因为构造函数调用可能会使用 helper link 赋值重新排序 从thread_2 来看。

但是在这篇文章中提到这种方法适用于 32 位原语。

Although the double-checked locking idiom cannot be used for references to objects, it can work for 32-bit primitive values (e.g., int's or float's). Note that it does not work for long's or double's, since unsynchronized reads/writes of 64-bit primitives are not guaranteed to be atomic.

// Correct Double-Checked Locking for 32-bit primitives
class Foo { 
  private int cachedHashCode = 0;
  public int hashCode() {
    int h = cachedHashCode;
    if (h == 0) 
    synchronized(this) {
      if (cachedHashCode != 0) return cachedHashCode;
      h = computeHashCode();
      cachedHashCode = h;
      }
    return h;
    }
  // other functions and members...
  }

请解释一下它为什么有效?我知道 32 位写入是原子的。

这里的局部变量是什么原因?

"DCL is broken" 比喻的实质是,使用 DCL 初始化单例对象,线程可以在看到对象处于完全初始化状态之前看到对该对象的引用。 DCL 充分同步引用单例的有效最终全局变量,但未能同步全局引用的单例对象。

在您的示例中,只有全局变量。没有"object to which it refers."