Java语言规范定义了section 17.5中最终字段的语义:
The usage model for final fields is a simple one. Set the final fields for an object in that object’s constructor. Do not write a reference to the object being constructed in a place where another thread can see it before the object’s constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object’s final fields. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are.
我的问题是 – ‘最新’保证是否扩展到嵌套数组和嵌套对象的内容?
简而言之:如果一个线程将可变对象图分配给对象中的最终字段,并且对象图永远不会更新,那么所有线程都可以通过最终字段安全地读取该对象图吗?
示例场景:
> Thread A构造一个ArrayLists的HashMap,然后将HashMap分配给类’MyClass’实例中的final字段’myFinal’
>线程B看到对MyClass实例的(非同步)引用并读取’myFinal’,并访问和读取其中一个ArrayLists的内容
在这种情况下,线程B看到的ArrayList的成员是否保证至少与MyClass的构造函数完成时一样最新?
我正在寻找澄清Java内存模型和语言规范的语义,而不是像同步这样的替代解决方案.我的梦想答案是肯定或否定,并参考相关文字.
更新:
>我对Java 1.5及更高版本的语义感兴趣,即通过JSR 133引入更新的Java内存模型.此更新中引入了最终字段的“最新”保证.
解决方法:
In this scenario, are the members of
the ArrayList as seen by Thread B
guaranteed to be at least as up to
date as they were when MyClass’s
constructor completed?
对,他们是.
第一次遇到引用时,需要一个线程来读取内存.由于构造了哈希映射,其中的所有条目都是全新的,因此对对象的引用与构造函数完成时的对象是最新的.
在初次遭遇之后,通常的可见性规则适用.因此,当其他线程更改最终引用中的非final字段时,另一个线程可能看不到该更改,但它仍会看到构造函数中的引用.
实际上,这意味着如果您不在构造函数之后修改最终哈希映射,则其内容是所有线程的常量.
编辑
我知道我以前见过这个保证.
以下是article中描述JSR 133的一段感兴趣的内容
Initialization safety
The new JMM also seeks to provide a
new guarantee of initialization safety
— that as long as an object is properly constructed (meaning that a
reference to the object is not
published before the constructor has
completed), then all threads will see
the values for its final fields that
were set in its constructor,
regardless of whether or not
synchronization is used to pass the
reference from one thread to another.
Further, any variables that can be
reached through a final field of a
properly constructed object, such as
fields of an object referenced by a
final field, are also guaranteed to be
visible to other threads as well. This
means that if a final field contains a
reference to, say, a LinkedList, in
addition to the correct value of the
reference being visible to other
threads, also the contents of that
LinkedList at construction time would
be visible to other threads without
synchronization. The result is a
significant strengthening of the
meaning of final — that final fields
can be safely accessed without
synchronization, and that compilers
can assume that final fields will not
change and can therefore optimize away
multiple fetches.