Analysis of the threadlocal principle of Java

Source: Internet
Author: User

Brief introduction

As early as the version of JDK 1.2, Java.lang.threadlocal,threadlocal provides a new way to solve the concurrency problem of multi-threaded threads. Using this tool class, you can write beautiful multithreaded programs very concisely. When you use threadlocal to maintain variables, Threadlocal provides a separate copy of the variable for each thread that uses the variable, so each thread can independently change its own copy without affecting the copy of the other thread. From the thread's point of view, the target variable is like a thread's local variable, which is the meaning of the "local" in the class name. Therefore, the code to write thread-local variables in Java is relatively clumsy, resulting in thread-local variables not being well-popularized in Java developers. From @ Maple's inverse it is often said that locks are a mechanism for changing space in time, and that threadlocal is just a space-changing time.

And lock comparison Why should we first emphasize this point, because from the introduction, it is easy to remind people that threadlocal seems to be a solution to the Java Multithreaded Environment thread synchronization and threading security method, in fact, here to design to two concepts: thread safety, thread synchronization, Threadlocal only solves the problem of thread safety, and does not solve the problem of thread synchronization, which also caused me to learn at the time, I always in instead focusing, threadlocal since for each thread copy a variable, then how to synchronize it? After checking a lot of information to understand, threadlocal is not used to solve the thread synchronization, so it and the lock can be said to have nothing to do with each other's strengths, can not be replaced. Some people describe this: Threadlocal solves the problem of resource sharing within the same thread, and synchronized solves the problem of resource sharing among multiple threads, and I think it makes sense! Recommended readers to look at the discussion paste, is about synchronized keywords and threadlocal, interested can look at, to discuss the post.

The following is a blog post from the reverse of @ Maple:

Threadlocal class interface is very simple, there are only 4 methods, let us first look at:

    • void set (T value) sets the value of the thread local variable for the current thread.
    • Public T Get () This method returns the thread local variable that corresponds to the current thread.
    • The public void Remove () Removes the value of the current thread local variable to reduce memory usage, which is a new method of JDK 5.0. It is important to note that when the thread ends, the local variables of the thread that should be used are automatically garbage collected, so it is not necessary to explicitly call the method to clear the thread's local variables, but it can speed up the memory reclamation.
    • Protected T InitialValue () returns the initial value of the thread's local variable, which is a protected method, apparently designed for subclasses to overwrite. This method is a deferred call method that executes only when the thread calls get () or set (T value) for the 1th time, and executes only 1 times. The default implementation in Threadlocal returns a null directly.

It is worth mentioning that, in JDK5.0, Threadlocal already supports generics, and the class name of the class has become threadlocal<t>. The API methods are also adjusted accordingly, and the new version of the API method is void set (t value), t get (), and T InitialValue (). How does threadlocal maintain a copy of a variable for each thread? The idea is simple: there is a map in the Threadlocal class that stores a copy of the variable for each thread, the key for the element in the map is the thread object, and the value corresponds to the variable copy of the thread. We can provide a simple implementation version by ourselves:

 Public classTestnum {//① Specifies the initial value by overwriting the Threadlocal InitialValue () method with an anonymous inner class    Private StaticThreadlocal<integer> SeqNum =NewThreadlocal<integer>() {           PublicInteger InitialValue () {return0;        }      }; //② getting the next sequence value     Public intGetnextnum () {Seqnum.set (Seqnum.get ()+ 1); returnSeqnum.get (); }         Public Static voidMain (string[] args) {testnum sn=NewTestnum (); //③ 3 threads sharing sn, each generating serial numbertestclient T1 =Newtestclient (SN); TestClient T2=Newtestclient (SN); testclient T3=Newtestclient (SN);          T1.start ();          T2.start ();      T3.start (); }        Private Static classTestClientextendsThread {PrivateTestnum SN;  Publictestclient (testnum sn) { This. SN =SN; }             Public voidrun () { for(inti = 0; I < 3; i++) {                  //④ 3 sequence values per threadSystem.out.println ("thread[" + thread.currentthread (). GetName () + "]--sn[" + sn.getnextnum () + "]"); }          }      }  }  

In general, we define the subclass of threadlocal by means of an anonymous inner class, providing the initial variable value, as shown in the example ①. TestClient threads produce a set of serial numbers, and at ③ we generate 3 testclient that share the same testnum instance. Run the above code and output the following results on the console:

THREAD[THREAD-0]-sn[1]
THREAD[THREAD-1]-sn[1]
Thread[thread-2]-sn[1]
THREAD[THREAD-1]-sn[2]
THREAD[THREAD-0]-sn[2]
THREAD[THREAD-1]-sn[3]
Thread[thread-2]-sn[2]
THREAD[THREAD-0]-sn[3]
Thread[thread-2]-sn[3]

Examining the results of the output, we find that each thread produces an ordinal number that shares the same Testnum instance, but they do not interfere with each other, but instead produce separate serial numbers, because we provide a separate copy of each thread through threadlocal.

Comparison of thread synchronization mechanisms

What are the advantages of threadlocal compared to the thread synchronization mechanism? Both the threadlocal and thread synchronization mechanisms are designed to address the access violation of the same variable in multiple threads. In the synchronization mechanism, the lock mechanism of the object guarantees that only one thread accesses the variable at the same time. At this time the variable is shared by multiple threads, using the synchronization mechanism requires the program to carefully analyze when to read and write variables, when to lock an object, when to release object locks and other complex problems, programming and writing is relatively difficult. Threadlocal, however, solves multiple threads of concurrent access from another angle. Threadlocal provides a separate copy of the variable for each thread, isolating the access violation of multiple threads to the data. Because each thread has its own copy of the variable, there is no need to synchronize the variable. Threadlocal provides thread-safe shared objects that can encapsulate unsafe variables into threadlocal when writing multithreaded code. Because the threadlocal can hold any type of object, the Get () provided by the lower version of the JDK returns an object, which requires a type cast. But JDK 5.0 solves this problem with generics, and simplifies the use of threadlocal to some extent, and listing 9 2 uses the new threadlocal<t> version of JDK 5.0.

To sum up, for the problem of multi-thread resource sharing, the synchronization mechanism adopts the way of "time-changing Space", and threadlocal adopts the way of "changing time by Space". The former provides only one copy of the variable, allowing different threads to queue access, and the latter provides a variable for each thread, so it can be accessed at the same time without affecting each other. Spring uses threadlocal to solve thread-safety problems we know that in general, only stateless beans can be shared in a multithreaded environment, and in spring, most beans can be declared as singleton scopes. is because spring is for some beans (such as Requestcontextholder, Transactionsynchronizationmanager, Localecontextholder, etc.) the non-thread-safe state is handled by threadlocal, making them also a thread-safe state, because stateful beans can be shared across multiple threads. The general Web application divides into the presentation layer, the service layer and the persistence layer three levels, writes the corresponding logic in the different layers, the lower layer through the interface to the upper layer open function calls. In general, all program calls from receiving requests to returning responses belong to one thread, as shown in:

The same thread runs through three layers so that you can store some non-thread-safe variables in threadlocal as needed, and in the same invocation thread of the same request response, all the associated objects are referenced to the same variable. The following example can reflect spring's idea of transforming a stateful bean: Listing 3 Testdao: non-thread safe

 Public class Testdao {      private Connection Conn;   ① A non-thread-safe  variable public      voidthrows  SQLException {          = Conn.createstatement (); // ② referencing non-thread-          safe variables // ...   ..     }  }  

Because the conn at ① is a member variable, because the Addtopic () method is non-thread-safe, a new Topicdao instance (not singleton) must be created when it is used. The following uses Threadlocal to transform Conn, a non-thread-safe "state": Listing 4 Testdao: Thread safety

 Public classTestdaonew {//① Saving connection variables using threadlocal    Private StaticThreadlocal<connection> connthreadlocal =NewThreadlocal<connection>();  Public StaticConnection getconnection () {//② If Connthreadlocal does not have a connection corresponding to this thread to create a new connection,//and save it in a thread-local variable.         if(Connthreadlocal.get () = =NULL) {Connection conn=getconnection ();              Connthreadlocal.set (conn); returnConn; } Else {              returnConnthreadlocal.get ();//③ directly returns thread-local variables        }      }         Public voidAddtopic ()throwsSQLException {//④ get thread-corresponding connection from threadlocalStatement stat =getconnection (). createstatement (); }  }  

When using Topicdao, different threads first determine if Connthreadlocal.get () is null, or NULL, indicating that the current thread does not have a corresponding connection object. At this point, a connection object is created and added to the local thread variable, and if it is not NULL, the current thread already has the connection object, which can be used directly. This ensures that different threads use thread-related connection and do not use the connection of other threads. Therefore, this topicdao can be done singleton share. Of course, this example itself is very rough, put connection threadlocal directly in DAO can only do this DAO's multiple methods share connection without thread safety problem, but can not be shared with other DAO the same connection, To do the same transaction multiple DAO shares the same connection, you must use Threadlocal to save the connection in a common external class. Connectionmanager.java

 Public classConnectionManager {Private StaticThreadlocal<connection> Connectionholder =NewThreadlocal<connection>() {@OverrideprotectedConnection InitialValue () {Connection conn=NULL; Try{conn=Drivermanager.getconnection ("Jdbc:mysql://localhost:3306/test", "username",                          "Password"); } Catch(SQLException e) {e.printstacktrace (); }              returnConn;        }      };  Public StaticConnection getconnection () {returnConnectionholder.get (); }         Public Static voidSetConnection (Connection conn) {Connectionholder.set (conn); }  }  
Threadlocal<t>

So how does the Threadlocal class implement this "provide a different copy of the variable for each thread"? Let's take a look at how the source code of the Threadlocal set () method is implemented:

/*** Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses would have a no need to * override this method, and relying solely on the {@link#initialValue} * method to set the values of Thread-locals. *     * @paramValue the value to is stored in the current thread's copy of * this thread-local. */      Public voidset (T value) {Thread T=Thread.CurrentThread (); Threadlocalmap Map=Getmap (t); if(Map! =NULL) Map.set ( This, value); ElseCreatemap (t, value); }  
Inside this method we see that we first get a threadlocalmap related to the current thread through the Getmap (thread T) method, and then set the value of the variable to the Threadlocalmap object, Of course, if the obtained Threadlocalmap object is empty, it is created by the Createmap method. The secret of thread isolation lies in the Threadlocalmap class. Threadlocalmap is a static inner class of the Threadlocal class that implements the setting and acquisition of key-value pairs (as compared to the map object), each of which has a separate threadlocalmap copy that stores values that can only be read and modified by the current thread. The Threadlocal class implements the isolation of variable access in different threads by manipulating a threadlocalmap copy of each line thread. Because the variables are unique to each thread, there is no concurrency error at all. Another thing is that the key in the Threadlocalmap stored key-value pair is the Threadlocal object that the this object points to, and the value is the object you set. To deepen our understanding, let's look at the implementation of the Getmap and Createmap methods that appear in the code above:
/*** Get The map associated with a ThreadLocal.  Overridden in * inheritablethreadlocal. *  * @paramt the current thread *@returnThe map*/threadlocalmap Getmap (Thread t) {returnt.threadlocals; }    /*** Create The map associated with a ThreadLocal.  Overridden in * inheritablethreadlocal. *  * @paramt the current thread *@paramFirstvalue value for the initial entry of the map *@parammap the map to store. */  voidCreatemap (Thread T, T firstvalue) {t.threadlocals=NewThreadlocalmap ( This, Firstvalue); }  

Then take a look at the Get () method in the Threadlocal class:
/*** Returns the value in the current thread's copy of this * thread-local variable. If the variable have no value for the ' current thread ', it is first initialized to the value returned * by an invocation of the {@link#initialValue} method. *  * @returnThe current thread ' s value of this thread-local*/   PublicT Get () {Thread T=Thread.CurrentThread (); Threadlocalmap Map=Getmap (t); if(Map! =NULL) {threadlocalmap.entry e= Map.getentry ( This); if(E! =NULL)              return(T) E.value; }      returnSetinitialvalue (); }  

Look again at the Setinitialvalue () method:

/*** Variant of Set () to establish initialvalue.     Used instead * of set () in case user has overridden the set () method. *     * @returnThe initial value*/     PrivateT Setinitialvalue () {T value=InitialValue (); Thread T=Thread.CurrentThread (); Threadlocalmap Map=Getmap (t); if(Map! =NULL) Map.set ( This, value); ElseCreatemap (t, value); returnvalue; }  

Analysis of the threadlocal principle of Java

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.