"最新"保证Java的最终字段的值是否延伸到间接引用?

mat*_*tbh 10 java memory concurrency synchronization final

Java语言规范定义了第17.5节中最终字段的语义:

最终字段的使用模型很简单.在该对象的构造函数中设置对象的最终字段.在对象的构造函数完成之前,不要在另一个线程可以看到的位置写入对正在构造的对象的引用.如果遵循此原因,那么当另一个线程看到该对象时,该线程将始终看到该对象的最终字段的正确构造版本.它还将看到那些最终字段引用的任何对象或数组的版本,这些字段至少与最终字段一样是最新的.

我的问题是 - '最新'保证是否扩展到嵌套数组和嵌套对象的内容?

简而言之:如果一个线程将可变对象图分配给对象中的最终字段,并且对象图永远不会更新,那么所有线程都可以通过最终字段安全地读取该对象图吗?

示例场景:

  1. 线程A构造一个ArrayLists的HashMap,然后在类'MyClass'的实例中将HashMap分配给final字段'myFinal'
  2. 线程B看到对MyClass实例的(非同步)引用并读取'myFinal',并访问和读取其中一个ArrayLists的内容

在这种情况下,线程B看到的ArrayList的成员是否保证至少与MyClass的构造函数完成时一样最新?

我正在寻找澄清Java内存模型和语言规范的语义,而不是像同步这样的替代解决方案.我的梦想答案是肯定或否定,并参考相关文字.

更新:

  • 我对Java 1.5及更高版本的语义感兴趣,即通过JSR 133引入更新的Java内存模型.此更新中引入了最新字段的"最新"保证.

Ale*_*yak 6

在这种情况下,线程B看到的ArrayList的成员是否保证至少与MyClass的构造函数完成时一样最新?

对,他们是.

第一次遇到引用时,需要一个线程来读取内存.因为构造了哈希映射,所以其中的所有条目都是全新的,然后对对象的引用up-to-date就是构造函数完成时的引用.

在初次遭遇之后,通常的可见性规则适用.因此,当其他线程更改最终引用中的非final字段时,另一个线程可能看不到该更改,但仍会看到构造函数中的引用.

实际上,这意味着如果您不在构造函数之后修改最终哈希映射,则其内容是所有线程的常量.

编辑

我知道我以前见过这个保证.

以下是本文中描述JSR 133 的一段感兴趣的内容

初始化安全

新的JMM还试图提供初始化安全性的新保证 - 只要对象被正确构造(意味着在构造函数完成之前未发布对象的引用),那么所有线程都将看到值它的最终字段是在其构造函数中设置的,无论是否使用同步将引用从一个线程传递到另一个线程.此外,任何可以通过正确构造的对象的最终字段到达的变量,例如最终字段引用的对象的字段,也保证对其他线程也是可见的.这意味着如果final字段包含对LinkedList的引用,除了对其他线程可见的引用的正确值之外,构造时该LinkedList的内容对于没有同步的其他线程也是可见的.结果是最终意义的显着增强 - 最终字段可以在没有同步的情况下安全地访问,并且编译器可以假设最终字段不会改变,因此可以优化多个提取.