The Threadlocal class in Java Multi-threading is not yet well understood, so here's a summary.
The main reference is the article in http://www.cnblogs.com/dolphin0520/p/3920407.html.
First, the understanding of threadlocal
ThreadLocal, many places are called thread-local variables, and some places are called thread-local storage, in fact, the meaning is similar. Maybe a lot of friends know that threadlocal a replica is created for a variable in each thread, each thread can access its own internal copy variable.
This sentence literally seems easy to understand, but the real understanding is not so easy.
Start with an example:
In this example, when the thread needs to manipulate the database, the OpenConnection method needs to be called from ConnectionManager, which returns a connection in Drivemanager and assigns a value to the class variable connect.
classConnectionManager {Private StaticConnection connect =NULL; Public StaticConnection OpenConnection () {if(Connect = =NULL) {Connect=drivermanager.getconnection (); } returnConnect; } Public Static voidCloseConnection () {if(connect!=NULL) Connect.close (); }}
Obviously, in multi-threading, this class is unsafe.
First, none of the 2 methods are synchronized, and it is likely that connect will be created multiple times in the OpenConnection method;
Second, because connect is a shared variable, it is necessary to use synchronization to ensure thread safety where connect is called, because it is likely that one thread is using Connect for database operations, while another thread calls CloseConnection to close the link.
Therefore, for thread-safety reasons, the two methods of this code must be synchronized, and synchronous processing is required where connect is called.
This will greatly affect the efficiency of the execution of the program, because when a thread uses connect for database operations, the other threads only wait.
So let's take a closer look at this question, does this place need to be shared with the connect variable? In fact, it is not necessary. If there is a connect variable in each thread, access to the connect variable between the threads is actually not dependent, i.e. one thread does not need to be concerned about whether the other thread has modified the connect.
Here, a friend may think that since you do not need to share this variable between threads, you can do this directly, create a database link in each method that needs to use the database connection, and then release the connection after the method call is complete. such as the following:
classConnectionManager {PrivateConnection connect =NULL; PublicConnection OpenConnection () {if(Connect = =NULL) {Connect=drivermanager.getconnection (); } returnConnect; } Public voidCloseConnection () {if(connect!=NULL) Connect.close (); }} classdao{ Public voidInsert () {ConnectionManager ConnectionManager=NewConnectionManager (); Connection Connection=connectionmanager.openconnection (); //use connection to operateconnectionmanager.closeconnection (); }}
There is really no problem with this processing, because each time a connection is created inside a method, there is no thread-safety problem between threads. However, this can have a fatal impact: causing the server to be very stressful and severely impacting program execution performance. Because the database connection needs to be opened and closed frequently in the method, this can not seriously affect the efficiency of the program execution, but also may cause the server pressure is huge.
It would be fitting to use threadlocal in this case, because threadlocal creates a copy of the variable in each thread, that is, there is a variable inside each thread that can be used anywhere inside the thread, and the threads do not affect each other. As a result, there is no thread-safety issue, and there is no serious impact on program execution performance.
Note, however, that although threadlocal is able to solve the above problem, due to the creation of replicas in each thread, it is important to consider the consumption of resources, such as memory usage, which is larger than threadlocal.
Second, in-depth analysis of threadlocal class
In the above talk about some of the understanding of threadlocal, then we look at how the specific threadlocal is implemented.
Let's look at some of the methods provided by the Threadlocal class:
Public T get () {} Public void set (T value) {} Public void remove () {} protected T InitialValue () {}
The Get () method is used to get a copy of the variable that threadlocal holds in the current thread, set () to make a copy of the variable in the current thread, and remove () to remove the copy of the variable in the current thread, InitialValue () is a protected method, It is generally used for rewriting when used, and it is a lazy loading method, which is described in detail below.
First, let's take a look at how the Threadlocal class creates a copy of a variable for each thread.
First look at the implementation of the Get method:
The first sentence is to obtain the current thread, and then get to a map,map type of Threadlocalmap by Getmap (t) method. Then get to the <key,value> key-value pair, and Note that this is what gets the key-value pair, not the current thread T.
If successful, the value is returned.
If map is empty, call the Setinitialvalue method to return value.
Each of our above sentences is carefully analyzed:
First look at what the Getmap method does:
What might not have occurred to you is that in Getmap, it is called the current thread T, which returns a member variable threadlocals in the present thread T.
So let's go ahead and take a look at the member variable threadlocals in the thread class:
is actually a threadlocalmap, this type is an inner class of the Threadlocal class, and we continue to take a look at the implementation of Threadlocalmap:
You can see that the entry of Threadlocalmap inherits WeakReference and uses threadlocal as the key value.
Then go on to see the concrete implementation of the Setinitialvalue method:
It is easy to understand, that is, if the map is not empty, set the key value pairs, empty, and then create a map, look at the implementation of Createmap:
At this point, most of your friends may have understood how threadlocal creates a copy of a variable for each thread:
First of all Within each thread, there is a member variable threadlocals of type Threadlocal.threadlocalmap, which is used to store the actual copy of the variable, the key value is the current threadlocal variable, and value is a copy of the variable ( Variable of type T).
Initially, in thread, Threadlocals is empty, and when the Get () method or set () method is called through the threadlocal variable, the threadlocals in the thread class is initialized. And with the current threadlocal variable as the key value, to threadlocal the copy variable to save as value, save to Threadlocals.
Then in the current thread, if you want to use a copy variable, you can find it in the threadlocals by using the Get method.
Here's an example of how the threadlocal can achieve the effect of creating a copy of a variable in each thread:
Public classTest {ThreadLocal<Long> longlocal =NewThreadlocal<long>(); ThreadLocal<String> stringlocal =NewThreadlocal<string>(); Public voidset () {Longlocal.set (Thread.CurrentThread (). GetId ()); Stringlocal.set (Thread.CurrentThread (). GetName ()); } Public LongGetlong () {returnLonglocal.get (); } PublicString getString () {returnStringlocal.get (); } Public Static voidMain (string[] args)throwsinterruptedexception {FinalTest test =NewTest (); Test.set (); System.out.println (Test.getlong ()); System.out.println (Test.getstring ()); Thread Thread1=NewThread () { Public voidrun () {test.set (); System.out.println (Test.getlong ()); System.out.println (Test.getstring ()); }; }; Thread1.start (); Thread1.join (); System.out.println (Test.getlong ()); System.out.println (Test.getstring ()); }}
The output of this code is:
From the output of this code, it can be seen that in the main thread and the THREAD1 thread, the longlocal saved copy values and Stringlocal saved copy values are not the same. The last time the copy value is printed again on the main thread is to prove that the replica values in the main thread and the THREAD1 thread are indeed different.
To summarize:
1) The actual copy created through threadlocal is stored in each thread's own threadlocals ;
2) Why the Threadlocals type Threadlocalmap's key value is Threadlocal object, because there can be more than one threadlocal variable in each thread, just like longlocal and stringlocal in the code above;
3) before the GET, must first set, otherwise it will report null pointer exception;
You must override the InitialValue () method if you want to have normal access without calling set before get.
Three, the threadlocal application scene
The most common threadlocal usage scenarios are used to resolve database connections, session management, and so on.
Such as:
Private Static New Threadlocal<connection>() { public Connection initialvalue () { return drivermanager.getconnection (db_url); Public Static Connection getconnection () { return connectionholder.get ();}
The following code is excerpted from:
http://www.iteye.com/topic/103804
Private Static FinalThreadLocal threadsession =NewThreadLocal (); Public StaticSession getsession ()throwsinfrastructureexception {Session s=(Session) threadsession.get (); Try { if(s = =NULL) {s=getsessionfactory (). Opensession (); Threadsession.set (s); } } Catch(Hibernateexception ex) {Throw NewInfrastructureexception (ex); } returns;}
Resources:
"In-depth understanding of Java virtual machines"
The idea of Java programming
http://ifeve.com/thread-management-10/
Http://www.ibm.com/developerworks/cn/java/j-threads/index3.html
http://www.iteye.com/topic/103804
http://www.iteye.com/topic/777716
http://www.iteye.com/topic/757478
http://blog.csdn.net/ghsau/article/details/15732053
http://ispring.iteye.com/blog/162982
Http://blog.csdn.net/imzoer/article/details/8262101
Http://www.blogjava.net/wumi9527/archive/2010/09/10/331654.html
http://bbs.csdn.net/topics/380049261
Java Multithreading (ii)--Deep anatomy threadlocal