Java concurrent programming combat - this quote escapes

        " Release and escape " is introduced in "Java Concurrent Programming Practice" , first introduce the release, and then focus on this reference escape .

1. Release

" Publishing " an object means making the object available for use in code outside the current scope.

E.g:

① Save a reference to the object to a place where other codes can access

②Return the reference in a non-private method

③ Pass the reference to the method of other classes

Let's look at a few specific examples:

① Save the reference of the object to a public static variable, so that any class and thread can see the object

import java.util.*;
 
/**
 * Secrets
 *
 * Publishing an object
 *
 * @author Brian Goetz and Tim Peierls
 */
class Secrets {
    
    
    public static Set<Secret> knownSecrets;
 
    public void initialize() {
    
    
        knownSecrets = new HashSet<Secret>();
    }
}
 
 
class Secret {
    
    
}

        As shown in the above code, a new HashSet object is instantiated in the initialize method, and a reference to the object is saved to knownSecrets to publish the object. How to understand it? If you add a Secret object to the collection knownSecets, this object will be released for a long time, because any code can traverse this collection and obtain a reference to this new Secret object.

②Return a reference from a non-private method, and also publish the returned object

/**
 * UnsafeStates
 * <p/>
 * Allowing internal mutable state to escape
 *
 * @author Brian Goetz and Tim Peierls
 */
class UnsafeStates {
    
    
    private String[] states = new String[]{
    
    
        "AK", "AL" /*...*/
    };
 
    public String[] getStates() {
    
    
        return states;
    }
}

        The above code array states has escaped its scope, because the variable that should have been private has been released.

③ When passing an object to an external method, it is equivalent to publishing the variable.

        Explain the "external method", a class C. For C, "external method" refers to methods whose behavior is not completely specified by C, including methods defined in other classes and methods that can be rewritten in class C (both Not a private method [private] nor a final method [final])

④ Publish an inner class, the inner class will automatically hold the this reference of its outer class

Second, escape

Escape refers to the release of an object that should not be released.

The escape of this reference means that the this reference is released before the object is constructed . It will involve thread safety issues, because other threads may access incomplete objects that have not been initialized through this escaped reference, and other objects may access objects that are initialized, which will cause inconsistency.

Let's look at an example provided in the book:

/**
 * ThisEscape
 * <p/>
 * Implicitly allowing the this reference to escape
 *
 * @author Brian Goetz and Tim Peierls
 */
public class ThisEscape {
    
    
    public ThisEscape(EventSource source) {
    
    
        source.registerListener(new EventListener() {
    
    
            public void onEvent(Event e) {
    
    
                doSomething(e);
            }
        });
    }
 
    void doSomething(Event e) {
    
    
    }
 
 
    interface EventSource {
    
    
        void registerListener(EventListener e);
    }
 
    interface EventListener {
    
    
        void onEvent(Event e);
    }
 
    interface Event {
    
    
    }
}

        As ThisEscape shows, when ThisEscape publishes EventListener, it also implicitly publishes the ThisEscape instance itself, because the instance of this inner class contains an implicit reference to the ThisEscape instance. When an object is released from the object's constructor, only an object that has not yet been constructed is released, even if the statement to release the object is in the last line of the constructor.

        The book also mentions a situation where this reference escapes, starting a thread in the constructor. When an object creates a thread in its constructor, whether it is created explicitly (by passing it to the constructor) or implicitly created (because Thread or Runnable is an internal class of the object), this reference will be newly created Thread sharing. Before the object is fully constructed, the new thread can see it.

Summarize the reasons for the escape of this reference:

The first case: inner class

① Created an inner class in the constructor

②In the constructor always publish the internal class

Solution:

Avoid ①② appearing at the same time, wait until the constructor is completed, and publish the internal class outside the constructor . The correct example is given in the book:

Through private constructor + public engineering method

/**
 * SafeListener
 * <p/>
 * Using a factory method to prevent the this reference from escaping during construction
 *
 * @author Brian Goetz and Tim Peierls
 */
public class SafeListener {
    
    
    private final EventListener listener;
 
    private SafeListener() {
    
    
        listener = new EventListener() {
    
    
            public void onEvent(Event e) {
    
    
                doSomething(e);
            }
        };
    }
 
    public static SafeListener newInstance(EventSource source) {
    
    
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }
 
    void doSomething(Event e) {
    
    
    }
 
 
    interface EventSource {
    
    
        void registerListener(EventListener e);
    }
 
    interface EventListener {
    
    
        void onEvent(Event e);
    }
 
    interface Event {
    
    
    }
}

The second case: start the thread in the constructor

① Constructor, create thread

②Start the thread in the constructor

Solution:

The thread is not started in the constructor. After the constructor is built, the thread is started outside

Guess you like

Origin blog.csdn.net/weixin_44556968/article/details/110006331