3.2. Publication and Escape
Publishing
an object means making it available to code outside of its current scope, such as by storing a reference to it where other code can find it, returning it from a nonprivate method, or passing it to a method in another class. In many situations, we want to ensure that objects and their internals are
not
published. In other situations, we do want to publish an object for general use, but doing so in a thread-safe manner may require synchronization. Publishing internal state
The most blatant form of publication is to store a reference in a public static field, where any class and thread could see it, as in Listing 3.5. The initialize method instantiates a new HashSet and publishes it by storing a reference to it into knownSecrets . Listing 3.5. Publishing an Object.
Publishing one object may indirectly publish others. If you add a Secret to the published knownSecrets set, you've also published that Secret , because any code can iterate the Set and obtain a reference to the new Secret . Similarly, returning a reference from a nonprivate method also publishes the returned object. UnsafeStates in Listing 3.6 publishes the supposedly private array of state abbreviations. Listing 3.6. Allowing Internal Mutable State to Escape. Don't Do this.
Publishing
states
in this way is
Publishing an object also publishes any objects referred to by its nonprivate fields. More
From the perspective of a class
C
, an
alien
method is one whose behavior is not fully specified by
C
. This includes methods in other classes as well as overrideable
Whether another thread actually does something with a published reference doesn't really matter, because the risk of misuse is still present.
[7]
Once an object
A final mechanism by which an object or its internal state can be published is to publish an inner class instance, as shown in ThisEscape in Listing 3.7. When ThisEscape publishes the EventListener , it implicitly publishes the enclosing ThisEscape instance as well, because inner class instances contain a hidden reference to the enclosing instance. Listing 3.7. Implicitly Allowing the this Reference to Escape. Don't Do this.
3.2.1. Safe Construction PracticesThisEscape illustrates an important special case of escapewhen the this references escapes during construction. When the inner EventListener instance is published, so is the enclosing ThisEscape instance. But an object is in a predictable, consistent state only after its constructor returns, so publishing an object from within its constructor can publish an incompletely constructed object. This is true even if the publication is the last statement in the constructor. If the this reference escapes during construction, the object is considered not properly constructed . [8]
{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %} A common mistake that can let the this reference escape during construction is to start a thread from a constructor. When an object creates a thread from its constructor, it almost always shares its this reference with the new thread, either explicitly (by passing it to the constructor) or implicitly (because the Thread or Runnable is an inner class of the owning object). The new thread might then be able to see the owning object before it is fully constructed. There's nothing wrong with creating a thread in a constructor, but it is best not to start the thread immediately. Instead, expose a start or initialize method that starts the owned thread. (See Chapter 7 for more on service lifecycle issues.) Calling an overrideable instance method (one that is neither private nor final ) from the constructor can also allow the this reference to escape. If you are tempted to register an event listener or start a thread from a constructor, you can avoid the improper construction by using a private constructor and a public factory method, as shown in SafeListener in Listing 3.8. Listing 3.8. Using a Factory Method to Prevent the this Reference from Escaping During Construction.
|