release and escape

Publish : Publishing an object means making the object available for use in code outside the current scope. E.g:

  • keep a reference to the object somewhere other code can access it;
  • Return the reference in a non-private method;
  • Pass references into methods of other classes.

Escape : When an object that shouldn't be released is released, the situation is called escaping.

1. The easiest way to publish an object is to store a reference to the object in a public static variable so that any class and thread can see the object.

public static Set<Secret> knownSecrets;

public void initialize(){
    knownSecrets = new HashSet<Secret>();
}

When an object is published, other objects may be published indirectly. For example, in the code above, if you add a Secret object to the collection knownSecrets, that object will also be published, because any code can traverse the collection and get a reference to the Secret object.

2. Similarly, if a reference is returned from a non-private method, the returned object will also be published.

class UnsafeStates{
    private String[] states = new String[]{
        "A","B","C"    
    };
    
    public String[] getStates(){ return states; }
}

When an object is published, all objects referenced in the object's non-private fields will be published. In general, if a published object can reach other objects through non-private variable references and method calls, then those objects will also be published.

"External method": Refers to methods whose behavior is not entirely defined by this class, including methods defined in other classes and methods in this class that can be overridden (neither private methods nor terminating [final] methods). When you pass an object to an external method, you publish the object.

3. Publish an instance of the inner class. The following code, when ThisEscape publishes the EventLinstener, implicitly publishes itself. Because the inner class holds a reference to the outer class by default.

public class ThisEscape{
    public ThisEscape(EventSource source){
        source.registerListener(
            new EventListener(){
                public void onEvent(Event e){
                    doSomething(e);
                }
            });
    }
}

Safe construction process:

In the above code, a special example is given in ThisEscape, where the this reference escapes in the constructor.

An object is in a predictable, consistent state if and only if its constructor returns. So when you publish an object from its constructor, you're just publishing an object that hasn't finished construction. This is true even if the release object statement is placed on the last line of the constructor. Such an object is considered incorrectly constructed if the this reference escapes in the constructor.

Safe release:

  • Immutable objects: meet all requirements of immutability: state is immutable, all fields are final, correct construction process.
  • Factual Immutable Objects: Objects are technically mutable, but their state doesn't change after they're published.
  • Mutable Objects: Objects can be modified after construction.
  1. Immutable objects can be safely accessed by any thread without the need for additional synchronization, even when those objects were released without synchronization.
  2. A de facto immutable object that is safely released can be safely used by any thread without additional synchronization.
  3. Mutable objects must be released in a safe manner, and must be thread-safe or protected by a lock.

Common patterns for secure release:

To safely release an object, the object's reference and the object's state must be visible to other threads at the same time. A properly constructed object can be released safely by:

  • Initialize an object reference in a static initialization function.
  • Save a reference to an object in a volatile type field or in an AtomicReferance object.
  • Store a reference to an object in a final type field where the object is properly constructed.
  • Save a reference to an object in a field protected by a lock.

In general, the easiest and safest way to publish a statically constructed object is to use a static initializer:

public static Holder holder = new Holder(42);

Static initializers are executed by the JVM during the initialization phase of a class. Due to the synchronization mechanism inside the JVM, any object initialized in this way can be released safely.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325279494&siteId=291194637