在http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html的底部,它说:
双重检查锁定不可变对象
如果 Helper 是一个不可变对象,这样 Helper 的所有字段都是最终的,那么双重检查锁定将起作用,而不必使用 volatile 字段。这个想法是对不可变对象(如字符串或整数)的引用应该与 int 或 float 的行为方式大致相同;对不可变对象的读写引用是原子的。
mutable one的示例和解释如下:
// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null)
synchronized(this) {
if (helper == null)
helper = new Helper();
}
return helper;
}
// other functions and members...
}
第一个原因,它不起作用
最明显的原因是初始化 Helper 对象的写入和对 helper 字段的写入可以完成或被认为是无序的。因此,调用 getHelper() 的线程可以看到对辅助对象的非空引用,但会看到辅助对象的字段的默认值,而不是构造函数中设置的值。
如果编译器内联对构造函数的调用,那么如果编译器可以证明构造函数不能抛出异常或执行同步,则初始化对象的写入和对辅助字段的写入可以自由地重新排序。
即使编译器不重新排序这些写入,在多处理器上,处理器或内存系统也可能重新排序这些写入,正如在另一个处理器上运行的线程所感知的那样。
我的问题是:为什么不可变类没有问题?我看不到重新排序与类是否可变的任何关系。
谢谢