Java basics of Java perplexed-ThreadLocal

Source: Internet
Author: User

Threadlocal is widely used in database connection and session management, and it is helpful to understand threadlocal's understanding of open source code such as struts and spring.

Threadlocal If you simply look at the name as a "local thread" that means that the name is really not very good, it is easy to misunderstand, threadlocalvariable (thread local variable) should be a better name. Let's take a look at the official description of Threadlocal:

This class provides thread-local (thread-local) variables. These variables are different from their ordinary counterparts, because each thread that accesses a variable (through its Get or set method) has its own local variable, independent of the initialized copy of the variable. ThreadLocal instances are typically private static fields in a class that want to associate the state with a thread (for example, a user ID or transaction ID).

    1. each thread has its own local variable , and each thread has a context that is separate from the other thread to hold the variable, and one thread's local variable is invisible to the other thread
    2. independent of the initialized copy of the variable , threadlocal can give an initial value, and each thread will get a copy of the initialization value to ensure that different threads have a copy.
    3. The state is associated with a thread , and ThreadLocal is not used to solve the problem of shared variables, not to reconcile thread synchronization, but to introduce a mechanism to facilitate each thread's handling of its own state. Understanding this is essential for proper use of threadlocal.
Threadlocal's Understanding

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.

Let's look at an example (referencing Java concurrency programming: delving into threadlocal):

class ConnectionManager {    privatestaticnull;    publicstaticopenConnection() {        ifnull){            connect = DriverManager.getConnection();        }        return connect;    }    publicstaticvoidcloseConnection() {        if(connect!=null)            connect.close();    }}

Obviously, there is a thread-safety problem with Multithreading: First, there are 2 methods that are not synchronized, and it is likely that connect is created multiple times in the OpenConnection method, and second, because connect is a shared variable, It is necessary to use synchronization to ensure thread safety when calling connect, because it is likely that one thread is using Connect for database operations, while another thread calls CloseConnection to close the link.
If the lock concept is used in connect, this will greatly affect the execution efficiency 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.

Then change the code further, each time new:

Class ConnectionManager {PrivateConnection connect =NULL; PublicConnectionOpenConnection() {if(Connect = =NULL) {connect = Drivermanager.getconnection (); }returnConnect } Public void CloseConnection() {if(connect!=NULL) Connect.close (); }}class dao{ Public void Insert() {ConnectionManager ConnectionManager =NewConnectionManager (); Connection Connection = Connectionmanager.openconnection ();//Use connection for OperationConnectionmanager.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.

parsing threadlocal Source code

Threadlocal has an internal class threadlocalmap, the implementation of this class accounted for the entire Threadlocal class source code more than half. The role of this threadlocalmap is critical, and it is a container for threads to actually save the thread's own local variables. Each thread has its own separate instance of Threadlocalmap, and all its local variables are saved to this map.

The threadlocal mainly provides:

publicget() { }publicvoidset(T value) { }publicvoidremove() { }protectedinitialValue() { }
    • The Get () method is used to get a copy of the variable that threadlocal holds in the current thread.
    • Set () sets a copy of the variables in the current thread.
    • Remove () Removes a copy of the variable in the current thread.
    • InitialValue () is a protected method that is typically used to override when used, and is a lazy loading method.

First, let's take a look at how the Threadlocal class creates a copy of a variable for each thread .

Get Method
     PublicTGet() {//Get current threadThread t = Thread.CurrentThread ();//Gets the Threadlocalmap instance of the current threadThreadlocalmap map = getmap (t);//If map is not empty, it means that the thread already has a Threadlocalmap instance        if(Map! =NULL) {//Map to save all thread local variables of thread, we are going to find the current thread local variableThreadlocalmap.entry e = Map.getentry ( This);//If the current thread local variable exists in this map, its corresponding value is returned            if(E! =NULL)return(T) E.value; }//If map does not exist or the current thread local variable does not exist in map, the initial value is returned        returnSetinitialvalue (); }

It is emphasized that thethread object has an attribute threadlocals of type Threadlocalmap, which is dedicated to saving all of its thread-local variables . This property is null when the thread object is initialized. Therefore, the Threadlocals property needs to be initialized for the first time that a thread object is used on a thread-local variable. Note that the "thread first uses local thread variable" and "use a thread-local thread variable for the first time" are distinguished.

Getmap method

//直接返回线程对象的threadLocals属性ThreadLocalMap getMap(Thread t) {        return t.threadLocals;}

Setinitialvalue method

privatesetInitialValue() {    // 获取初始化值,initialValue 就是我们之前覆盖的方法    T value = initialValue();    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    // 如果map不为空,将初始化值放入到当前线程的ThreadLocalMap对象中    ifnull)        map.set(this, value);    else        // 当前线程第一次使用本地线程变量,需要对map进行初始化工作        createMap(t, value);    // 返回初始化值    return value;}

Createmap Method:

    void createMap(Thread t, T firstValue) {        new ThreadLocalMap(this, firstValue);    }

At this point, most of your friends may have understood how threadlocal creates a copy of a variable for each thread:

First, there is a member variable threadlocals for the Threadlocal.threadlocalmap type within thread thread, and this threadlocals is used to store the actual copy of the variable, The key value is the current thread threadlocal variable, and value is a variable copy (that is, a 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 thread threadlocal variable as the key value, to threadlocal the copy variable to save as value, and 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.

Set Method
publicvoidset(T value) {     Thread t = Thread.currentThread();     ThreadLocalMap map = getMap(t);     ifnull)         map.set(this, value);     //说明线程第一次使用线程本地变量(注意这里的第一次含义)     else         createMap(t, value); }
Remove Method
publicvoidremove() {     //获取当前线程的ThreadLocalMap对象     ThreadLocalMap m = getMap(Thread.currentThread());     //如果map不为空,则删除该本地变量的值     ifnull)         m.remove(this); }
Example

proves that the effect of creating a copy of a variable in each thread can be achieved by threadlocal

 Public classTest {threadlocal<long> longlocal =NewThreadlocal<long> (); Threadlocal<string> stringlocal =NewThreadlocal<string> (); Public void Set() {longlocal.Set(Thread.CurrentThread (). GetId ()); Stringlocal.Set(Thread.CurrentThread (). GetName ()); } Public Long Getlong() {returnLonglocal.Get(); } PublicStringgetString() {returnStringlocal.Get(); } Public Static void Main(string[] args) throws interruptedexception {final Test test =NewTest (); Test.Set(); System. out. println (Test.getlong ()); System. out. println (Test.getstring ()); Thread Thread1 =NewThread () { Public void Run() {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 ()); }}

Results:
1
Main
12
Thread-0
1
Main

Can be understood as:
In the threadlocals of longlocal
Key:main thread's threadlocal variable, value:1
key:thread-0 the current threadlocal variable of the thread, Value:12

In the threadlocals of stringlocal
Key:main thread's threadlocal variable, value:main
key:thread-0 the current threadlocal variable of the thread, value:thread-0

Application Scenarios

The most common threadlocal usage scenarios are used to resolve database connections, session management , etc.
 

privatestaticnew ThreadLocal<Connection>() {publicinitialValue() {    return DriverManager.getConnection(DB_URL);}};publicstaticgetConnection() {return connectionHolder.get();}
private  static  final  ThreadLocal threadsession = new  ThreadLocal (); public  static  Session getsession  () throws     Infrastructureexception {Session S = (session) Threadsession.get (); try  {if  (s = = null ) {s = Getsessionfac            Tory (). Opensession ();        Threadsession.set (s); }} catch  (Hibernateexception ex) {throw  new  infrastructureexception (ex); } return  s;}  
Compare with synchronized

The Synchronized keyword mainly solves the problem of multi-threaded shared data synchronization .
Threadlocal mainly solves the problem that the data in multi-threading is inconsistent with concurrency .

Both threadlocal and synchonized are used to solve multi-threaded concurrent access. But there is an essential difference between threadlocal and synchronized:

Synchronized is the mechanism by which a lock is used so that a variable or block of code can be accessed by only one thread at a time. Instead, Threadlocal provides a copy of the variable for each thread, so that each thread accesses the same object at a certain time, isolating data sharing from multiple threads. Synchronized, in contrast, is used to gain data sharing when communicating between multiple threads.

Synchronized is used for data sharing between threads, while threadlocal is used for data isolation between threads. Of course threadlocal is not a substitute for synchronized, they deal with different problem domains. Synchronized is used to implement synchronization mechanisms and is more complex than threadlocal.

How does threadlocal maintain a copy of a variable for each thread? In fact, the idea of implementation is simple, there is a map in the Threadlocal class that stores a copy of each thread's variable.

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.

Object Release Issues

Reference: JAVA threadlocal Object Analysis
How does the thread local variable be recycled when we use the threadlocal process, after the thread ends?

First, the map that holds the thread local variable is not a member variable of threadlocal, but a member variable of Java.lang.Thread. In other words, when the thread ends, the map's resources are also recycled.
Analytical:
Threadlocal's Set,get method obtains the map in the following way:

ThreadLocalMap map = getMap(t);

The code for the Getmap method is as follows:

ThreadLocalMap getMap(Thread{return t.threadLocals;}

Code Snippet 2
Visible: The Threadlocalmap instance is stored as a member variable of java.lang.Thread, and each thread has a unique threadlocalmap. This map takes the Threadlocal object as key and the thread local variable as the value, so you can save multiple thread local variables under one thread. The operation of the threadlocal, the actual delegate to the current thread, each thread will have its own independent Threadlocalmap instance, the storage warehouse is entry[] Table;entry key is threadlocal, Value is the storage content, so in the concurrency environment, there is no problem with the set or get of threadlocal. The following is the storage diagram for thread local variables:

Storage diagram for "Thread local variables"

Since Treadlocalmap is a member variable of Java.util.Thread, Threadlocal is the key value in Threadlocalmap, and only one thread local variable can be saved in one. The benefits of Threadlocalmap as a member variable of the thread class are:

A. When a thread dies, the threadlocalmap is recycled, and the saved thread local variable can be reclaimed at the same time if no other references exist.

B. Under the same thread, you can have multiple treadlocal instances, saving multiple "thread local variables."

If threads are in the thread pool, always there, and threadlocal in multiple places, will it cause threadlocal objects not to be recycled?

 Public classTestmain { Public Static void Main(string[] args) { while(true) { for(intj =0; J <Ten; J + +) {NewThreadlocaldomail (New byte[1024x768*1024x768]). Getandprint (); }}}}class threadlocaldomail{Privatethreadlocal<byte[]> threadlocal=Newthreadlocal<byte[]> (); Public  Threadlocaldomail(byte[] b) {threadLocal.Set(b); } Public byte[]Getandprint(){byte[] b=threadlocal.Get(); System. out. println (B.length);returnb }}

Code Snippet 3

Because Threadlocalmap's entry is a (WeakReference) weak reference, when the Threadlocal object is no longer referenced externally, the threadlocal corresponding key and its value in the thread map are freed, without causing a memory overflow. The new threadlocaldomail in the Testmain code above is discarded after each loop, can be reclaimed by the garbage collector, and the code can be run continuously without memory overflow.

Reference:
Java concurrency programming: deep anatomy threadlocal
Easy to use threads: not sharing is sometimes the best
Synchronized Key Words Summary
Deep understanding of Threadlocal
A brief analysis of JAVA threadlocal objects

Java basics of Java perplexed-ThreadLocal

Related Article

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.