sne*_*egi 1 java multithreading
当我向JMM提出与“最终”相关的担保时,我最近感到困惑。这是JMM的摘录和示例
图4给出了一个示例,该示例演示了最终场与正常场的比较。类FinalFieldExample有一个最终整数字段x和一个非最终整数y。一个线程可以执行方法writer(),而另一个线程可以执行方法reader()。因为writer()在对象的构造函数完成之后写入f,所以将保证reader()可以看到fx的正确初始化值:它将读取值3。因此,不能保证reader()方法的值是4
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的困惑是,对象'Obj'具有final和non-final字段是否已完全初始化并由线程'T'引用,T将仅看到final字段的正确值吗?构造后不会发生突变的非最终字段呢?我了解,如果在构造线程“ T”之后对其进行了突变,则可能看不到新值(除非该字段为volatile)。但是,如果该领域是非最终性和非易失性的,并且在构造之后没有发生变化,我该怎么办?
JVM如何实现与“最终”相关联的保证?例如,对于易失性,存在存储障碍。
此问题已解决:
报价:
问题围绕指令的优化和重新排序。当您有两个正在使用构造对象且没有同步的线程时,出于效率考虑,编译器可能会决定对指令重新排序,并为对象分配内存空间,然后在构造函数和构造函数完成之前将其引用存储在item字段中。字段初始化。或者,它可以重新排序内存同步,以便其他线程以这种方式感知它。
如果将字段标记为final,它将强制编译器在构造函数完成之前完成对该字段的初始化。非最终字段没有此类保证。
这是Java语言定义(17.4)的一部分。有关final字段的详细信息,请参见JLS(17.5)。
更具体地说,该writer()方法构造的实例FinalFieldExample并将其存储在static字段中以供其他线程使用。由于指令重新排序,该y字段可能尚未初始化。如果同一线程调用,reader()它将被y视为,4但其他线程可能会将其视为,0因为在初始化和发布之前f可能已被设置和使用。 y
为了使这个代码是正确的,你必须f要volatile为好。