我们知道将字段设置为 final 通常是一个好主意,因为我们获得了线程安全性和不变性,这使得代码更容易推理。我很好奇是否有相关的性能成本。
Java 内存模型保证了这一点final Field Semantics
:
只有在对象完全初始化后才能看到对该对象的引用的线程可以保证看到该对象的最终字段的正确初始化值。
这意味着对于这样的课程
class X {
X(int a) {
this.a = a;
}
final int a;
static X instance;
}
每当线程 1 创建这样的实例时
X.instance = new X(43);
while (true) doSomethingEventuallyEvictingCache();
线程 2 看到了
while (X.instance == null) {
doSomethingEventuallyEvictingCache();
}
System.out.println(X.instance.a);
它必须打印 43。没有final
修饰符,JIT 或 CPU 可以重新排序存储(首先存储X.instance
然后设置a=43
),线程 2 可以看到默认初始化值并打印 0。
当 JIT 看到final
它时,它显然会避免重新排序。但它也必须强制 CPU 服从命令。是否存在相关的性能损失?