During initialization of a shared object, the object must only be accessible only to the thread constructing it. However, the object can be published safely (that is, made visible to other threads) once it its initialization is initializedcomplete. The Java Memory Model (JMM) allows multiple threads to observe the object after its initialization has begun, but before it has concluded. Consequently, it is important to ensure that allowing publication of a partially initialized object is not publishedforbidden.
This rule prohibits publishing a reference to a partially initialized member object instance before initialization has concluded. Rule TSM01-J. Do not let the (this) reference escape during object construction prohibits the this
reference of the current object from escaping.
...
Code Block | ||
---|---|---|
| ||
class Foo { private Helper helper; public Helper getHelper() { return helper; } public void initialize() { helper = new Helper(42); } } public class Helper { private int n; public Helper(int n) { this.n = n; } // ... } |
If a thread accesses were to access helper
using the getHelper()
method before the initialize()
method has been calledexecuted, the thread will would observe an uninitialized helper
field. Later, if one thread calls initialize()
, and another calls getHelper()
, the second thread could observe one of the following:
...
In particular, the JMM permits compilers to allocate memory for the new Helper
object and to assign it a reference to that memory to the helper
field before initializing itthe new Helper
object. In other words, the compiler can reorder the write to the helper
instance field with and the write that initializes the Helper
object (that is, this.n = n
) so that the former occurs first. This exposes can expose a race window during which other threads may can observe a partially-initialized Helper
object instance.
There is a separate issue: if two threads more than one thread were to call initialize()
, then two multiple Helper
objects are would be created. This is only a performance issue and not a correctness issue because n
will – correctness would be preserved. The n
field of each object would be properly initialized and the unused Helper
object (or objects) will eventually be garbage-collected.
Compliant Solution (Synchronization)
The Appropriate use of method synchronization can prevent publication of references to partially constructed object references can be prevented by using method synchronization-constructed objects, as shown in this compliant solution.
...
Synchronizing both methods guarantees that they will not cannot execute concurrently. If one thread calls were to call initialize()
just before another thread calls getHelper()
, the synchronized initialize()
method will always finish first. The synchronized
keywords establish a happens-before relationship between the two threads. This guarantees that Consequently, the thread calling getHelper()
sees would see either the fully initialized Helper
object or none at all an absent Helper
object (that is, helper
contains would contain a null
reference). This approach guarantees proper publication both for both immutable and for mutable members.
Compliant Solution (Final Field)
If the helper
field is declared final, it is guaranteed to The Java Memory Model guarantees that fields that are declared final will be fully constructed before its any reference to the containing object is made visible.
Code Block | ||
---|---|---|
| ||
class Foo { private final Helper helper; public Helper getHelper() { return helper; } public Foo() { // Point 1 helper = new Helper(42); // Point 2 } } |
Wiki Markup |
---|
However, this solution requires the assignment of a new {{Helper}} instance to {{helper}} from Foo's constructor. According to the _Java Language Specification_, Section 17.5.2, "Reading Final Fields During Construction" \[[JLS 2005|AA. Bibliography#JLS 05]\] |
...
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="239ebba5574c454f-4858a3cd-40a149a4-b6c3a49f-da9f15cc508e7c2a881f99f0"><ac:plain-text-body><![CDATA[ | [[API 2006 | AA. Bibliography#API 06]] |
| ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="59b374f939986631-dee5a30a-4f1e4a7e-9ec08c8c-def314e45606add982d26ed9"><ac:plain-text-body><![CDATA[ | [[Bloch 2001 | AA. Bibliography#Bloch 01]] | Item 48: "Synchronize access to shared mutable data" | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="8b3070f51d7c58f0-365ee3f6-4c4645be-a97caa62-e7447aa52c0063215257e8bc"><ac:plain-text-body><![CDATA[ | [[Goetz 2006 | AA. Bibliography#Goetz 06]] | Section 3.5.3 "Safe Publication Idioms" | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="823a9b4db9e33b75-a846d092-45004056-a343ad6f-1aa0156af20e7e477e1e445c"><ac:plain-text-body><![CDATA[ | [[Goetz 2007 | AA. Bibliography#Goetz 07]] | Pattern #2: "one-time safe publication" | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="a8c69e74ea8bcd31-097a9d33-46094d98-bbe5b181-2cb842786ed57352f9970cfe"><ac:plain-text-body><![CDATA[ | [[JPL 2006 | AA. Bibliography#JPL 06]] | 14.10.2. "Final Fields and Security" | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="5a48723140302720-d2de3928-42e0453c-b31992eb-40ab035f6b75676b403ec0a7"><ac:plain-text-body><![CDATA[ | [[Pugh 2004 | AA. Bibliography#Pugh 04]] |
| ]]></ac:plain-text-body></ac:structured-macro> |
...