How do finite fields prevent other threads from seeing partially constructed objects?

I looked for creating an immutable data type with final fields (including an array that was constructed and populated before assigning the element to the final field), and noticed that the JVM seems to be specified to ensure that any other thread that gets a reference to this object will see the initialized fields and values โ€‹โ€‹of the array (if the pointer to this not indicated in the constructor, see What is a "partially constructed object"? and How do hidden JVM memory barriers behave when creating a chain of constructors? ).

I am curious how this is achieved without synchronizing each access to this object or in any other way a significant decrease in performance is paid. In my opinion, the JVM can achieve this by doing the following:

  • Print a record at the end of the constructor
  • Publish a link to a new object only after recording
  • Perform a read-pick anytime you refer to the final field of an object

I cannot come up with a simpler or cheaper way to eliminate the risk of other threads considering uninitialized leaf fields (or recursive links through leaf fields).

It seems like this can impose a severe penalty for performance because of all the reading barriers in other threads reading the object, but the elimination of capitalization leads to the fact that the reference to the object is examined in another processor before it issues a reading or viewing updates in places memory corresponding to the newly initialized end fields.

Does anyone know how this works? And does this mean a significant decrease in productivity?

+8
java concurrency
source share
1 answer

See the "Memory Locks" section in this entry .

A StoreStore requires a barrier after setting the final fields and before binding the object to another variable. This is a key piece of information that you are asking for.

According to the Reordering section, the storage of the final field cannot be reordered relative to the storage of references to the object containing the final field.

In addition, it states that in v.afield = 1; x.finalField = v; ... ; sharedRef = x; v.afield = 1; x.finalField = v; ... ; sharedRef = x; none of the first two can be reordered with respect to the third; which ensures that the storages in the fields of the object that are stored as the final field are themselves guaranteed to be visible to other threads before the reference to the object containing the final field is saved.

Together, this means that all storages up to the final fields must be visible to all streams before the reference to the object containing the field is saved.

+4
source share

All Articles