About ThreadLocal

Source: Internet
Author: User

When talking about Handler's logoff, we talked about how to obtain and set logoff through ThreadLocal, as shown below:

Static final ThreadLocal <Looper> sThreadLocal = new ThreadLocal <lolocal> ();

When preparing logoff,

Public static void prepare () {if (sThreadLocal. get ()! = Null) {throw new RuntimeException ("Only one Looper may be created per thread");} sThreadLocal. set (new Looper ());}

When obtaining a logoff,

/*** Return the loginobject associated with the current thread. returns * null if the calling thread is not associated with a logoff. */public static logoff mylogoff () {return sThreadLocal. get ();}

So what is the role of ThreadLocal? Why does ThreadLocal appear?

First, let's take a look at the following example:

Public class HelperTesting {private String text = "empty"; private static HelperTesting helperTesting = new HelperTesting (); private void printText () {System. out. println (text);} private void changeText (String str) {text = str;} private void printWithLine (String str) {System. out. println ("####################" + str + "########### ##################");} public static void main (String [] args) {helperTesting. printWithLine (Thread. currentThread (). getName () + "start"); helperTesting. printText (); Thread thread = new Thread (new Runnable () {@ Override public void run () {helperTesting. printWithLine (Thread. currentThread (). getName () + "start"); helperTesting. printText (); helperTesting. changeText ("thread1"); helperTesting. printText (); helperTesting. printWithLine (Thread. currentThread (). getName () + "end") ;}}); thread. start (); try {thread. join ();} catch (InterruptedException e) {e. printStackTrace ();} helperTesting. printText (); helperTesting. printWithLine (Thread. currentThread (). getName () + "end ");}}


In this Demo, we have done the following:

1) create a HelperString object with a text field whose initial value is "empty ".

2) create a new thread, change the text value of the helperString object to "thread1" in the thread, run the thread, and print its value.

3) Finally, we print the text value in the original thread.

The running result is as follows:

##################### Main start ################# ############ empty ##################### Thread-0 start ## ########################### emptythread1 ############ ######### Thread-0 end ########################### ### thread1 #################### main end ############## ###############

We can see that the text value in the main thread is changed.

In the multi-threaded programming process, because thread shares the same process space, the running of thread A is entirely likely to change A value inadvertently, when Line B gets this value, it may not be the value it wants to obtain.

So someone wondered whether the thread could have some private space, so that the value stored in this space would not be changed by other threads, and this was the appearance of ThreadLocal.

Note that it is only used to ensure the privacy of Thread data, not to solve the synchronization problem between threads. I guess this is why it is called Thread Local.

Next, let's use a Demo to see how to use ThreadLocal, as shown below:

Public class HelperTestingSec {private ThreadLocal <String> sThreadLocal = new ThreadLocal <String> (); private static HelperTestingSec helperTesting = new HelperTestingSec (); private HelperTestingSec () {sThreadLocal. set ("empty");} private void printText () {System. out. println (sThreadLocal. get ();} private void changeText (String str) {sThreadLocal. set (str);} private void printWithLine (String str) {System. out. println ("####################" + str + "########### ##################");} public static void main (String [] args) {helperTesting. printWithLine (Thread. currentThread (). getName () + "start"); helperTesting. printText (); Thread thread = new Thread (new Runnable () {@ Override public void run () {helperTesting. printWithLine (Thread. currentThread (). getName () + "start"); helperTesting. printText (); helperTesting. changeText ("thread1"); helperTesting. printText (); helperTesting. printWithLine (Thread. currentThread (). getName () + "end") ;}}); thread. start (); try {thread. join ();} catch (InterruptedException e) {e. printStackTrace ();} helperTesting. printText (); helperTesting. printWithLine (Thread. currentThread (). getName () + "end ");}}

What we did in this Demo is actually similar to the previous Demo. The only difference is that in this Demo, we use a ThreadLocal object to store the String value. The running result is as follows:

##################### Main start ################# ############ empty ##################### Thread-0 start ## ########################### nullthread1 ############ ######### Thread-0 end ########################### ### empty #################### main end ############## ###############

From the above results, we can see that in the main thread of the same helperTestingSec object, the object stored in sThreadLocal is always empty.

In the new thread, the value of changeText is null before it is called to set the value. That is to say, although it is the same object in the new thread, but its values are different. Even if we change its value in the new thread, it will not affect its value in the Main thread.

It can be seen that through ThreadLocal, we have achieved data independence between threads.

So what is the implementation principle of ThreadLocal and why can it achieve this? We still want to know its internal structure and see if we can learn something, right.

In order, in general, we always put things in first, and then get things out, so let's take a look at the ThreadLocal set method first.

One thing to note is that the ThreadLocal implementation described here is the implementation in Android. The implementation methods in JDK are a bit different, but the principle is the same.

Public void set (T value) {Thread currentThread = Thread. currentThread (); Values values = values (currentThread); if (values = null) {values = initializeValues (currentThread);} values. put (this, value );}

In Demo2, when we call the set method of sThreadLocal, we enter the above logic.

As you can see, the first step is to use Thread. currentThread to get the current Thread, and then get an object called Values according to this Thread. Let's look at the values function. We can see where the Values object is obtained, as shown below:

/*** Creates Values instance for this thread and variable type. */Values initializeValues (Thread current) {return current. localValues = new Values ();}/*** Gets Values instance for this thread and variable type. */Values values (Thread current) {return current. localValues ;}

It can be seen that the value object is obtained from the current thread. If this object does not exist, it will call the initializeValues method to create a new value object for the localValues of the thread.

Recently, we call the put method of values to store our valule in this Values object with the current ThreadLocal object as the key value. We will immediately realize that, values implements a data structure similar to Map key-value pairs.

From here, we can realize that:

1) there is a Values object in each thread.

2) no matter which thread we call the ThreadLocal object, we will first obtain a Values object in the current thread (if it does not exist, create one) and then perform key-value operations on this Values object, for example, the ThreadLocal Get method is as follows:

Public T get () {// Optimized for the fast path. Thread currentThread = Thread. currentThread (); Values values = values (currentThread); if (values! = Null) {Object [] table = values. table; int index = hash & values. mask; if (this. reference = table [index]) {return (T) table [index + 1] ;}} else {values = initializeValues (currentThread);} return (T) values. getAfterMiss (this );}

3) a ThreadLocal object can be shared to all threads, because it is only used as an entry and a WeakRefreence Key value. The real data is stored in Values, this Values object is unique to the thread and is unique in the current thread.

That's why sThreadLocal is a static object in the logoff class.

The internal implementation of Values actually uses an Object array as the data structure, with an even number (, 4 ....) as the Key value, it is stored as a WeakReference pointing to the ThreadLocal object itself, odd digits (1, 3, 5 ....) as the Value, it stores the Value we set. From the get method above, we can also look at it a little.

Here, we recommend articles on both sides to help you understand ThreadLocal.

When and how to use a ThreadLocal
How is ThreadLocal implemented?



About 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.