我正在阅读Java®语言规范Java SE 8版并且 17.5。最终的字段语义有一个例17.5-1。 Java内存模型中的最终字段(https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5)。
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; // guaranteed to see 3
int j = f.y; // could see 0
}
}
}
说明状态:
一个线程可能会执行方法编写器而另一个线程可能会执行 方法读者。 因为writer方法在对象的构造函数之后写入f 完成后,读者方法将保证正确看到 f.x的初始化值:它将读取值3.但是,f.y是 不是最终的;因此,读者方法无法保证看到 价值4。
我用两个线程编写了一些代码来重现这种情况但是当 reader 方法返回4以外的其他东西时我无法获得这种情况?总是将构造函数设置为4。
也许我无法理解。我将很感激地澄清这一点。
修改 谢谢大家,特别是 assylias 。 Testing initialization safety of final fields完全向我解释。对我来说,这些句子是最重要的:
从Java 5.0开始,您将保证所有线程都能看到最终结果 由构造函数设置的状态。
实际上是确保构造函数在任何之前完成 随后的计划行动发生
答案 0 :(得分:0)
通常,使用多线程应用程序很难获得所有可能性(特别是如果涉及缓存)。甚至不可能总是在所有JVM或操作系统或CPU上获得所有可能的结果。
假设以下内容: 线程1:使用writer方法创建f。 线程2:调用reader()。
为什么读者看到f非null和f.y与4不同?答案是,本地缓存可用于优化代码。比f创建,但y的值尚未更改。
编辑: "官方"回答,杰里米曼森可以找到here。 (感谢assylias'评论)