Java concurrency Programming (ii) Release and thread closure of objects

Source: Internet
Author: User
Tags event listener

Release and escape of objects

Publish (Publish) an object that allows an object to be used in code outside the current scope. There are three ways that can be implicitly referenced in a constructed method through public static variables , non-private methods .

If the object is published before it is constructed, thread security is broken. This is known as escaping (Escape) When an object that should not be published is published.

Let's start by looking at how an object escapes.

The simplest way to publish an object is to save the object's reference to a common static variable so that any class and thread can see the object, such as the following code.

public static set<string> Myset;public Void Initialize () {MySet = new hashset<string> ();}


When you publish an object, other objects may be published indirectly. If you add a String object to the collection MySet, the object is also published because any code can traverse the collection and get a reference to the string object. Similarly, if a reference is returned from a non-private method , the returned object is also published. As the following code Unsafestates publishes an array of states that should have been private.

Class Unsafestate {private string[] states = new string[] {"AK", "AL"};p ublic string[] GetStates () {return states;}}


If the states is published according to the appeal method, there will be a problem, because any caller can modify the contents of this array. The array states has overflowed its scope because the variable that should have been private has been released. When a private variable is published, the class does not know what the "external method" will do.

It doesn't matter what other threads do with references to a semantic publication, because the risk of misusing the reference always exists. When an object in Hadoop escapes, you must assume that there is a class or thread that might misuse the object. This is the main reason for the need to use encapsulation: encapsulation can make it possible to analyze correctness and reduce the behavior of inadvertently destroying design constraints.

The last mechanism to publish an object or its internal state is to publish an internal class instance, as shown in the following class Thisescape. When Thisescape publishes EventListener, it also implicitly publishes the Thisescape instance itself, because an instance of the inner class contains an implicit object to the Thisescape instance.

public class Thisescape {public Thisescape (EventSource source) {Source.registerlistener (new EventListener () {public void OnEvent (Event e) {dosomething (e);}});}}

The construction process of security

A special example of escaping is given in Thisescape, where this reference escapes in the constructor. When an internal EventListener instance is published, the externally encapsulated Thisescape instance also escapes. The object is in a predictable and consistent state when and only if the object's constructor returns . Therefore, when you publish an object from the object's constructor, only one object that has not yet been constructed is published. This is true even if the statement of the publication object is in the last row of the constructor. If this reference escapes during construction, then such an object is considered to be constructed incorrectly.

A common mistake in making this reference escape during construction is to start a thread in the constructor. When an object creates a thread in its constructor, whether the display is created (by passing it to the constructor) or implicitly (because thread or Runnable is an inner class of the object), the This reference is shared by the newly created thread. The new thread can see it until the object has been created. Creating a thread in the constructor is not an error, but it is best not to start it immediately, but to start with a start or Initialize method. Invoking a rewritable instance method in a constructor can also cause the this reference to escape during the construction process.

If you want to register an event listener or a startup thread in the constructor, you can use a private constructor and a common factory method (Factory) to avoid improper construction procedures, such as the following Safelistener.

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;}}

Thread closure

Synchronization is often required when accessing shared mutable data. One way to avoid using synchronization is to not share data. If data is accessed only in single-wire range, no synchronization is required. This technique, called thread confinement, is one of the simplest ways to implement thread-safe. This usage automatically implements thread safety when an object is enclosed in a thread, even if the enclosing object itself is not thread-safe.

A common application of thread closure is the Connection object of JDBC. The JDBC specification does not require that the Connection object be thread-safe. In a typical server application, a thread obtains a Connection object from the connection pool, and uses that object to process the request, and then returns the object to the connection pool when it is finished. Because most requests, such as Servlet requests or EJB calls, are handled synchronously by a single thread, and the connection pool does not assign it to other threads until the Connection object is returned, the connection management mode implicitly processes the request The Connection object is enclosed in a thread.

The Java language and its core libraries provide mechanisms to help maintain thread closeness, such as local variables and ThreadLocal classes, even though the programmer still needs to ensure that objects in the enclosing thread do not escape from the threads.


Ad-hoc Thread Closure

Ad-hoc thread closure means that the responsibility for maintaining thread closeness is fully implemented by the program. Ad-hoc thread closure is very fragile because there is no language feature, such as a visibility modifier or a local variable, that encloses an object on the target thread. In fact, references to thread-closed objects, such as visual components or data models in GUI applications, are usually stored in public variables.

When you decide to use thread closure technology, it is usually because you want to implement a particular subsystem as a single-threaded subsystem. In some cases, the simplicity of a single-threaded subsystem is better than the vulnerability of the AD-HOC thread-blocking technology.

There is a special thread closure on volatile variables. As long as you can ensure that only a single thread performs write operations on shared volatile variables, you can safely perform read-modify-write operations on these shared volatile variables. In this case, it is equivalent to enclosing the modify operation in a single thread to prevent a race condition, and the visibility guarantee of the volatile variable ensures that other threads can see the most recent value.

Because of the fragility of the AD-HOC thread closure technology, it should be used sparingly in the program and, where possible, stronger threading techniques (for example, a stack closure or a threadlocal class) should be used.


Stack closure

Stack closure is a special case of thread closure, where objects can only be accessed through local variables in a stack closure. Just as encapsulation makes it easier for code to maintain invariant conditions, synchronous variables can also make objects more easily enclosed in threads.

For basic types of local variables, such as the numpairs of the Loadtheark method below, there is no way to break the stack closure anyway. This semantics of the Java language ensures that local variables of the underlying type are always enclosed within the thread, since no method is given a reference to the base type.

public int Loadtheark (collection<animal> candidates) {    sortedset<animal> animals;    int numpairs = 0;    Animal candidate = null;    Animals are enclosed in methods, do not let them escape!    animals = new Treeset<animal> (new Speciesgendercomparator ());    Animals.addall (candidates);    for (Animal a:animals) {        if (candidate = = NULL | |!candidate.ispotentialmate (a))            candidate = A;        else {            ark.load (new Animalpair (candidate, a));            ++numpairs;            candidate = null;        }    }    return numpairs;}

When maintaining the stack closure of object references, programmers need to do more to ensure that the referenced objects do not escape. Instantiates a TreeSet object in Loadtheark and saves a reference to the object to animals. At this point, only one reference to the collection animals, which is enclosed in a local variable, is also enclosed in the execution thread. However, if a reference to the collection animals (or any internal data within that object) is published, the closure is destroyed and the object animals escaped.

If a non-thread-safe object is used in the thread's internal (within-thread) context, then the object is still threads-safe. However, be careful that only developers who write code know which objects need to be closed to the execution thread, and whether the closed objects are thread-safe. If these requirements are not explicitly stated, subsequent maintainers can easily make the object escape by mistake.


ThreadLocal class

A more canonical way to maintain thread closeness is to use threadlocal, a class that associates a value in a thread with the object that holds the value . Threadlocal provides access interfaces or methods such as get and set, which have a separate copy of each thread that uses the variable, so get always returns the most recent value set by the current execution thread when it calls set.

Threadlocal objects are typically used to prevent the sharing of mutable single-instance variables (Singleton) or global variables . For example, in a single-threaded application, you might maintain a global database connection and initialize the Connection object at program startup to avoid passing a connection object when each method is called. Because JDBC connection objects are not necessarily thread-safe, it is not thread-safe when multithreaded applications use global variables without synergy. By saving the JDBC connection to the Threadlocal object, each thread will have its own connection.

This technique can be used when a frequently performed operation requires a temporary object, such as a buffer, while at the same time wanting to avoid reassigning the temporary object each time it is executed. For example, before Java 5.0, the Integer.tostring () method uses the Threadlocal object to hold a 12-byte buffer to format the result, Instead of using a shared static buffer (which requires the use of a lock mechanism) or allocating a new buffer each time it is called.

When a thread first calls the Threadlocal.get method, it calls InitialValue to get the initial value. Conceptually, you can think of threadlocal<t> as containing map< thread,t> objects that hold values specific to that thread, but threadlocal implementations are not. These thread-specific values are saved in the thread object, and when the thread terminates, the values are garbage collected.

Suppose you need to port a single-threaded application into a multithreaded environment, and you can maintain thread safety by converting shared global variables to threadlocal objects (if the semantics of global variables allow). However, if you convert an application-scoped cache to a thread-local cache, it does not have much effect.

Threadlocal is used extensively when implementing the application framework. For example, during an EJB call, the Java EE container needs to associate a transaction context (Transaction context) with a thread in execution. By saving the transaction context in a static Threadlocal object, you can easily implement this function: When the framework code needs to determine which transaction is currently running, simply read the transaction context from the Threadlocal object. This mechanism is convenient because it avoids passing execution context information when each method is called, but it also uses the mechanism's code to be coupled with the framework.

Developers often misuse threadlocal, such as all global variables as threadlocal objects, or as a means of "hiding" method parameters. Threadlocal variables are similar to global variables, which can reduce the reusability of code and introduce implicit coupling between classes, so use caution when using them.

Java concurrency Programming (ii) Release and thread closure of objects

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.