Java 不可变 类 与易变引用

Java immutable classes vs. volatile references

向其他线程发布值的标准做法是将构造的对象分配给 volatile 字段:作为双向内存栅栏的副作用,通过这种方式读取对象的线程字段保证不会看到部分构造的对象。 但是,如果 class 中的所有字段都是 final,那么对其构造函数的调用将自动处于与任何客户端代码的 happens-before 关系中,而无需参考文献需要 volatile 关键字。

  1. 后者是否比前者有性能优势(从读者的角度来看)?
  2. 这是否意味着 final 字段会产生性能成本(例如,它不仅在语义上而且在执行上实际上等同于易失性访问)?

Aleksey Shipilёv 对此有 an article

2014年,在他的具体硬件OS和Java版本上,他得出了这样的结论:

The performance costs for these idioms are usually drowned in all other costs. In the singleton examples above, while the costs are measurable, the cost of allocation, or the cost of additional memory dereference may greatly offset the cost of the safe initialization/publication pattern itself.

简短的回答是,它值得在您的 JVM 上进行基准测试,CPU。和 OS 的选择,因为答案将取决于这些因素以及代码中这些操作的频率(因此 JIT 决定如何处理它们)。

不过我想直觉地说,有了 final 字段,编译器对字段的使用方式有了更多的确定性,因此它可以使用简单、有效的优化。它可以在具有最终字段的构造函数之后放置一个内存屏障来满足内存保证。

对于 volatile 字段,编译器需要做更多的工作来确定什么是安全的,并且可能需要避免执行其他优化,例如重新排序 reads/writes.