【发布时间】:2016-02-03 03:05:40
【问题描述】:
这是来自JCiP的示例。
public class Unsafe {
// Unsafe publication
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
}
public class Holder {
private int n;
public Holder(int n) {
this.n = n;
}
public void assertSanity() {
if (n != n) {
throw new AssertionError("This statement is false.");
}
}
}
在第 34 页:
[15] 这里的问题不是 Holder 类本身,而是 持有人未正确发布。然而,持有人可以免疫 通过将 n 字段声明为最终字段来进行不当发布,这 会使 Holder 不可变;
来自this answer:
final 的规范(参见@andersoj 的回答)保证 当构造函数返回时,最终字段将正确 已初始化(从所有线程可见)。
来自wiki:
例如,在 Java 中,如果对构造函数的调用具有 已内联,则共享变量可能会立即更新一次 存储已被分配但在内联构造函数之前 初始化对象
我的问题是:
因为:(可能是错的,我不知道。)
a) 可以在内联构造函数初始化对象之前立即更新共享变量。
b) 只有在构造函数返回时,才能保证最终字段正确初始化(从所有线程可见)。
是否有可能另一个线程看到holder.n 的默认值? (即,另一个线程在 holder 构造函数返回之前获得对 holder 的引用。)
如果是这样,那你如何解释下面的陈述?
可以通过声明 n 来使持有人免受不当发布的影响 字段是最终的,这将使 Holder 不可变
编辑: 来自 JCiP。不可变对象的定义:
如果满足以下条件,则对象是不可变的:
x 它的状态在之后不能被修改 建造;x 它的所有字段都是最终的;[12] 和
x 它是正确的 构造(在构造过程中 this 引用不会转义)。
因此,根据定义,不可变对象不存在“this 引用转义”问题。对吧?
但是如果没有声明为 volatile,他们会在双重检查锁定模式中遭受Out-of-order writes 的影响吗?
【问题讨论】:
-
Java 内存模型保证安全发布,无需显式同步所有实例字段声明为 final 的不可变对象。
-
@scottb 不正确。构造函数本身可以泄漏引用。
标签: java multithreading immutability publish