Deep understanding of Threadlocal

Source: Internet
Author: User

Learn a thing first to know why to introduce it, is what we can use it to do. So let's take a look at what threadlocal does for us, and then see how it works.

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).
we pick out the key points:


1. Each thread has its own local variable

Each thread has a context that is separate from the other threads to hold the variable, and the local variables of one thread are not visible to other threads (with the premise, explained later)

2, independent of the initialization of the variable copy

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 and a certain line Threads association

ThreadLocal is not used to solve the problem of shared variables, not to reconcile thread synchronization, but to facilitate the introduction of a mechanism for each thread to handle its own state, understanding this is critical to the correct use of ThreadLocal.

Let's look at a simple example:

public class Threadlocaltest {//Create an Integer thread-local variable public static final Threadlocal<integer> Loc        Al = new Threadlocal<integer> () {@Override protected Integer InitialValue () {return 0;    }    };        public static void Main (string[] args) throws Interruptedexception {thread[] threads = new THREAD[5];                for (int j = 0; J < 5; J + +) {Threads[j] = new Thread (new Runnable () {@Override  public void Run () {//Gets the local variable of the current thread, and then accumulates 5 times int num =                    Local.get ();                    for (int i = 0; i < 5; i++) {num++;                    }//Reset the cumulative local variable local.set (num);                 System.out.println (Thread.CurrentThread (). GetName () + ":" + local.get ());        }}, "thread-" + j); } for (Thread thRead:threads) {Thread.Start (); }    }}

post-run results:

Thread-0:5
Thread-4:5
Thread-2:5
Thread-1:5
Thread-3:5

As we can see, each thread's cumulative result is 5, each thread processes its own local variable value, and the threads do not affect each other.

Let's look at another example:

public class Threadlocaltest {private static Index num = new index ();        Create a local variable of Index type private static threadlocal<index> local = new threadlocal<index> () {@Override        Protected Index InitialValue () {return num;     }    };        public static void Main (string[] args) throws Interruptedexception {thread[] threads = new THREAD[5];                for (int j = 0; J < 5; J + +) {Threads[j] = new Thread (new Runnable () {@Override public void Run () {//takes out local variables of the current thread and accumulates 1000 times index index = Loca                    L.get ();                    for (int i = 0; i <; i++) {index.increase ();                 } System.out.println (Thread.CurrentThread (). GetName () + ":" + index.num);        }}, "thread-" + j); } for (Thread thread:threads) {            Thread.Start ();         }} static class Index {int num;        public void Increase () {num++; }    }}

after execution we found the following results (each run is not the same):


Thread-0:1390
Thread-2:2390
Thread-4:4390
Thread-3:3491
Thread-1:1390

Why does the thread local variable fail again this time? You can look carefully at the above code to find out the reason first.

-----------------------------------------------low-key split-line-------------------------------------------

Let's take another look. "Threadlocal can give an initial value, and each thread will get a copy of this initialization value." "Copy of initial value ... "It seems to think of something." Let's take a look at the places in the code above that define threadlocal.

    private static Index num = new index ();    private static threadlocal<index> local = new threadlocal<index> () {        @Override        protected Index InitialValue () {            return num;       Note that this returns the already defined object num, not the new Index ()        }    ;

In the above code, we provide an initial value for our threadlocal by overriding the InitialValue function, and each thread gets a copy of the initial value. And now our initial value is a well-defined object, and num is a reference to that object. In other words our initial value is a reference. Is the referenced copy and reference pointing to the same object?

What if we want to save an index object for each thread? That is to create a copy of the object instead of the object reference:

private static threadlocal<index> local = new threadlocal<index> () {        @Override        protected Index InitialValue () {            return new Index ();///Note here        }    };

Copy diagram of the object:

Now we should be able to understand the meaning of threadlocal local variables. Next we will look at the source of threadlocal, from the inside to reveal its mystery.

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. Now let's start with the two most common methods of threadlocal get and set:

Public T get () {    //Gets the current thread of execution threads    T = Thread.CurrentThread ();    Gets the Threadlocalmap instance of the current thread    threadlocalmap map = getmap (t);    If map is not empty, the thread already has a Threadlocalmap instance if    (map! = null) {        //map all thread-local variables in the save thread, we are going to find the current thread local variable        Threadlocalmap.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 the map does not exist or the current thread local variable does not exist in the map, return the initial value of return    setinitialvalue ();}

It is emphasized that the thread 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:

Returns the Threadlocals property of the thread object directly threadlocalmap Getmap (thread t) {        return t.threadlocals;}
Setinitialvalue Method: (Look at the previous example after reading it)

Private T Setinitialvalue () {    //Get initialization value, InitialValue is the method we covered previously    T value = InitialValue ();    Thread t = thread.currentthread ();    Threadlocalmap map = getmap (t);    If map is not empty, put the initialization value into the Threadlocalmap object of the current thread if    (map! = null)        Map.set (this, value);    else        //When a local thread variable is first used by the front thread, the map needs to be initialized to work        Createmap (t, value);    Returns the initialization value of    return to value;}

Let's take a look at the Set method

public void Set (T value) {     Thread T = Thread.CurrentThread ();     Threadlocalmap map = getmap (t);      if (map! = null)         Map.set (this, value);     The description thread uses thread-local variables for the first time (note the first meaning here)     else         createmap (t, value);}

Thradlocal also has a remove method, let's analyze:

public void Remove () {     //Gets the current thread's Threadlocalmap object     threadlocalmap m = Getmap (Thread.CurrentThread ());     If map is not empty, the value of the local variable is deleted if     (M! = null)         m.remove (this);}

here everyone should be more clear about the threadlocal variable, as to the implementation of THRADLOCALMAP details here is not said. We are interested to see the source of threadlocal.


Deep understanding of Threadlocal

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.