你们每个人都知道JMM的这个特性,有时候对象的引用可以在完成这个对象的构造函数之前获得值.
在JLS7中,p.17.5 最后的字段语义我们也可以阅读:
final字段的使用模型很简单:final在该对象的构造函数中设置对象的字段; 并且在对象的构造函数完成之前,不要在另一个线程可以看到的地方写入对正在构造的对象的引用.如果遵循这一点,那么当另一个线程看到该对象时,该线程将始终看到该对象的final字段的正确构造版本.(1)
在JLS之后,接下来的示例演示了如何不保证非最终字段的初始化(1Example 17.5-1.1) (2):
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 …Run Code Online (Sandbox Code Playgroud) Java语言规范定义了第17.5节中最终字段的语义:
最终字段的使用模型很简单.在该对象的构造函数中设置对象的最终字段.在对象的构造函数完成之前,不要在另一个线程可以看到的位置写入对正在构造的对象的引用.如果遵循此原因,那么当另一个线程看到该对象时,该线程将始终看到该对象的最终字段的正确构造版本.它还将看到那些最终字段引用的任何对象或数组的版本,这些字段至少与最终字段一样是最新的.
我的问题是 - '最新'保证是否扩展到嵌套数组和嵌套对象的内容?
简而言之:如果一个线程将可变对象图分配给对象中的最终字段,并且对象图永远不会更新,那么所有线程都可以通过最终字段安全地读取该对象图吗?
示例场景:
在这种情况下,线程B看到的ArrayList的成员是否保证至少与MyClass的构造函数完成时一样最新?
我正在寻找澄清Java内存模型和语言规范的语义,而不是像同步这样的替代解决方案.我的梦想答案是肯定或否定,并参考相关文字.
更新: