Java final&;安全出版物
当我读到有疑问的“在新JMM下最终字段如何工作?”时,它说:Java final&;安全出版物,java,final,safe-publication,Java,Final,Safe Publication,当我读到有疑问的“在新JMM下最终字段如何工作?”时,它说: class FinalFieldExample { final int x; int y; static FinalFieldExample f; public FinalFieldExample() { x = 3; y = 4; } static void writer() { f = new FinalFieldExample(); } static void reader
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x;
int j = f.y;
}
}
}
上面的类是如何使用final字段的示例。线程执行读取器保证看到f.x的值3,因为它是最终值。不能保证看到y的值4,因为它不是最终值
这让我感到困惑,因为writer中的代码不是安全的发布,线程执行读取器可能会看到f不是null,但是f引用的对象的构造函数尚未完成,因此即使x是final,线程执行读取器也不能保证看到f.x的值3
这是我困惑的地方,如果我错了,请纠正我,非常感谢。这就是重点,这就是JMM中最后字段的优点。是的,编译器通常可以在对象完全构造之前为对象分配引用,这是不安全的发布,因为对象可能在部分构造状态下访问。但是,对于final字段,JMM(和编译器)保证在将引用分配给对象之前,首先准备所有final字段。发布可能仍然不安全,并且当新线程访问该对象时,该对象仍然只是部分构造,但至少最终字段将处于预期状态。从Java并发实践中的第16.3章: 初始化安全性仅保证值的可见性 在构造函数创建时,可通过最终字段访问的 完成。对于可通过非最终字段访问的值,或 施工后可能会发生变化,必须使用同步来确保 能见度
我还建议阅读第16.3章了解更多详细信息。
线程执行读取器可能会看到f不为null,但f引用的对象的构造函数尚未完成
这不可能发生,赋值发生在构造函数运行到完成之后,没有引发异常。哪种机制确保赋值发生在构造函数运行到完成之后,他说,编译器转换可以改变代码,使Helper构造函数中的代码在写入Helper变量之后发生。我认为jsr-133-faq中的代码与Jeremy Manson博客中的代码相同。