我正在研究创建一个具有最终字段的不可变数据类型(包括在分配给最终成员字段之前构造和填充的数组),并注意到似乎指定 JVM 以保证任何其他获得的线程对该对象的引用将看到已初始化的字段和数组值(假设this
在构造函数中没有发布指向的指针,请参阅什么是“未完全构造的对象”?以及链接构造函数时 JVM 的隐式内存屏障如何表现?)。
我很好奇这是如何在不同步对该对象的每次访问或以其他方式支付一些重大性能损失的情况下实现的。据我了解,JVM可以通过以下方式实现:
- 在构造函数的末尾发出写栅栏
- 仅在写栅栏之后发布对新对象的引用
- 每当您引用对象的最终字段时发出阅读围栏
我想不出一种更简单或更便宜的方法来消除其他线程看到未初始化的最终字段(或通过最终字段的递归引用)的风险。
这似乎会由于读取对象的其他线程中的所有读取栅栏而造成严重的性能损失,但消除读取栅栏会引入对象引用在另一个处理器发出读取之前被看到的可能性。 fence 或以其他方式查看与新初始化的最终字段相对应的内存位置的更新。
有谁知道这是如何工作的?这是否会带来显着的性能损失?