这篇文章说:
在这个不合规的代码示例中,Helper 类通过将其字段声明为 final 使其不可变。JMM 保证不可变对象在它们对任何其他线程可见之前被完全构造。getHelper() 方法中的块同步保证所有可以看到 helper 字段的非空值的线程也将看到完全初始化的 Helper 对象。
public final class Helper {
private final int n;
public Helper(int n) {
this.n = n;
}
// Other fields and methods, all fields are final
}
final class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) { // First read of helper
synchronized (this) {
if (helper == null) { // Second read of helper
helper = new Helper(42);
}
}
}
return helper; // Third read of helper
}
}
但是,此代码不能保证在所有 Java 虚拟机平台上都能成功,因为在 helper 的第一次读取和第三次读取之间没有发生之前的关系。因此,第三次读取 helper 有可能获得一个陈旧的空值(可能是因为它的值被编译器缓存或重新排序),导致 getHelper() 方法返回一个空指针。
我不知道该怎么办。我同意一读和三读之间没有发生之前的关系,至少没有直接的关系。从某种意义上说,第一次读取必须在第二次之前发生,第二次读取必须在第三次之前发生,因此第一次读取必须在第三次之前发生时,是否存在传递性发生在之前的关系?
有人能更专业地阐述吗?
慕尼黑5688855
www说
小怪兽爱吃肉
相关分类