Java Deep understanding of Threadlocal__java

Source: Internet
Author: User
Tags static class thread class

I believe that readers also read a lot of information about threadlocal on the internet, many bloggers say this: Threadlocal provides a new way to solve the concurrency problem of multithreaded programming; The purpose of threadlocal is to solve the shared problem of multi-threaded access to resources. If you think so, it now gives you 10 seconds to clear the wrong perception of threadlocal.

See how the source code in the JDK is written:

This class provides thread-local variables. These variables differ from their normal counterparts in so each thread that accesses one (via its
{@code Get}/{@code set} Method] has its own, independently initialized copy of the variable. {@code ThreadLocal} instances are typically private static fields in classes-Wish to associate state with a thread (E . G., a user ID or Transaction ID).
The translation is probably like this (English is not good, if there is a better translation, please leave a note):

The Threadlocal class is used to provide local variables within the thread. When accessed in a multithreaded environment (accessed through a Get or set method), this variable guarantees that the variable Chengri by each line is relatively independent of the variables in the other thread. Threadlocal instances are usually private static types that are used to correlate the context of threads and threads.

Can be summed up as a sentence: the role of threadlocal is to provide local variables within the thread, which function in the lifecycle of a thread, reducing the complexity of the delivery of some common variables between multiple functions or components within the same threads.
For example, I need to take the bus to do the subway before I go out. Here the bus and the subway is like two functions in the same thread, I am a thread, I want to complete both functions need the same thing: bus cards (Beijing bus and subway are using bus cards), So I'm not passing the bus card variable to either of these functions (which is equivalent to not always taking the bus card on the road), I can do this: give the bus card in advance to an organization, when I need to swipe the card to the organization to the public transport cards (of course, each take is the same bus card). This will achieve the purpose of the organization as long as I (the same thread) need a bus card, where and when.

Someone is going to say: You can set the bus card as a global variable ah, this is not also can when and where can take the bus card. But if there are many individuals (many threads). We can not all use the same bus card (we assume that the bus card is a real-name certification), so that is not a mess. Now you see. This is the original purpose of the threadlocal design: to provide local variables within the thread, and to isolate other threads within this thread wherever and whenever it is desirable. threadlocal Basic Operations

Constructors

The threadlocal's constructor signature is this:

/**
* Creates a thread local variable.
* @see #withInitial (java.util.function.Supplier)
*/
Public ThreadLocal () {
}
I didn't do anything inside. InitialValue function

The InitialValue function is used to set the initial value of the threadlocal, and the function signature is as follows:

Protected T InitialValue () {
return null;
}
The function is invoked the first time when the Get function is called, but the function is not invoked if the set function is called at the beginning. Typically, the function is invoked only once, unless the Remove function is called manually, and the Get function is called, in which case the InitialValue function is called in the Getting function. The function is protected type, obviously it is recommended to overload the function in a subclass, so the function is typically overloaded as an anonymous inner class to specify the initial value, such as:

Package com.winwill.test;
/**
 * @author Qifuguang
 * @date 15/9/2 00:05 * * Public
class Testthreadlocal {
    private static final T hreadlocal<integer> value = new threadlocal<integer> () {
        @Override
        protected Integer InitialValue () {return
            integer.valueof (1);}}
    ;
}
Get function

This function is used to get the value of the threadlocal associated with the current thread, and the function signature is as follows:

Public T Get ()
If the current thread does not have the value of the threadlocal, the InitialValue function is called to get the initial value returned. Set function

The set function is used to set the value of the threadlocal for the current thread, and the function is signed as follows:

public void Set (T value)
Sets the value of the threadlocal for the current thread. Remove function

The Remove function is used to delete the value of the current thread's threadlocal binding, and the function signature is as follows:

public void Remove ()
In some cases, this function needs to be called manually to prevent memory leaks. Code Demo

After learning the basics, we use a piece of code to illustrate the use of threadlocal, an example that implements the following scenario:

There are 5 threads, each of which has a value of 5, the initial value is 0, and the thread runs with a loop to add the number to the value value.

Code implementation:

Package com.winwill.test;
/**
 * @author Qifuguang
 * @date 15/9/2 00:05 * * Public
class Testthreadlocal {
    private static final T hreadlocal<integer> value = new threadlocal<integer> () {
        @Override
        protected Integer InitialValue () {return
            0;
        }
    };
    public static void Main (string[] args) {for
        (int i = 0; i < 5; i++) {
            new Thread (New Mythread (i)). Start (); 
  }
    }
    static class Mythread implements Runnable {
        private int index;
        Public mythread (int index) {
            this.index = index;
        }
        The initial value of the public void Run () {
            System.out.println (thread + index +): "+ value.get ());
            for (int i = 0; i < i++) {Value.set (
                value.get () + i);
            }
            SYSTEM.OUT.PRINTLN (cumulative value of "Thread + Index +": "+ value.get ());}}}

The results of the execution are:

Initial value:0 of thread 0
Initial value:0 of Thread 3
Initial value:0 of Thread 2
Cumulative value:45 of Thread 2
Initial value:0 of thread 1
Cumulative value:45 of Thread 3
Cumulative value:45 of thread 0
Cumulative value:45 of Thread 1
Initial value:0 of Thread 4
Cumulative value:45 of Thread 4

As you can see, the value of each thread is independent of each other, the cumulative operation of this thread will not affect the value of other threads, really achieve the effect of internal isolation of threads.

How to achieve the

Read the basic introduction, but also saw the simplest effect of the demonstration, we should be a good study of the implementation of the internal threadlocal principle. If you design, how would you design. I believe most people will have this idea:

Each threadlocal class creates a map and then uses the thread's ID as the key of the map, and the instance object acts as the value of the map, thus achieving the effect of the values isolation of each thread.

Yes, this is the simplest design, as the JDK's earliest threadlocal was designed to do. JDK1.3 (not sure whether it is 1.3) after the design of the threadlocal changed a way.

Let's take a look at the source code for JDK8 's threadlocal get method:

Public T get () {
      Thread t = thread.currentthread ();
      Threadlocalmap map = getmap (t);
      if (map!= null) {
          Threadlocalmap.entry e = Map.getentry (this);
          if (e!= null) {
              @SuppressWarnings ("unchecked")
              T result = (t) e.value;
              return result;
          }
      return Setinitialvalue ();
  }

One of the Getmap source:

Threadlocalmap Getmap (Thread t) {return
    t.threadlocals;
}
Setinitialvalue function Source code:

private T Setinitialvalue () {
    T value = InitialValue ();
    Thread t = thread.currentthread ();
    Threadlocalmap map = getmap (t);
    if (map!= null)
        Map.set (this, value);
    else
        createmap (t, value);
    return value;
}

Createmap function of the source code:

void Createmap (Thread T, T firstvalue) {
    t.threadlocals = new Threadlocalmap (this, firstvalue);

Simply parse, the process of the Get method is this:
1. Get the current thread first
2. Get a map from the current thread
3. If you get a map that is not empty, get the corresponding value E in the map with the threadlocal reference as the key, otherwise go to 5
4. If e is not null, return e.value, otherwise go to 5
5. Map is empty or E is empty, get the initial value value through the InitialValue function, and then create a new map with threadlocal references and value as Firstkey and Firstvalue
Then notice that the thread class contains a member variable:

Threadlocal.threadlocalmap threadlocals = null;
So, you can summarize the design idea of threadlocal:
Each thread maintains a THREADLOCALMAP mapping table, the key of which is the threadlocal instance itself, and value is the object that really needs to be stored.
This scenario is just the opposite of the simple design we started talking about. Looked at the data, this design mainly has the following advantages: So after the design of each map of the number of entry smaller: Before the number of thread, now is the number of threadlocal, can improve performance, is said to improve performance is not a little two points (no parental test) When the thread is destroyed, the corresponding Threadlocalmap is destroyed, which can reduce the amount of memory used.
Just a little bit deeper.

First of all, the fact that Threadlocalmap is using the weak reference of threadlocal as key:

Static class Threadlocalmap {
        /**
         * The entries in this hash map extend WeakReference, using
         * It main ref fi Eld as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get ()
         * = = NULL) mean that the key is no longer referenced, so the
         * entry can be Expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        Static class Entry extends Weakreference<threadlocal<?>> {
            /** the value associated with this Th Readlocal. *
            /Object value;
            Entry (threadlocal<?> K, Object v) {
                super (k);
                Value = V;
            }
        }
        ...
        ...
}

The following illustration is a reference diagram between some of the objects described in this article, where the solid lines represent strong references and dashed lines represent weak references:

Then there is the rumor on the web that threadlocal will cause a memory leak, and their reason is this:
As shown above, Threadlocalmap uses Threadlocal's weak reference as a key, and if a threadlocal has no external strong reference to reference him, then the system GC, the threadlocal is bound to be recycled, so that In Threadlocalmap, the key is null entry, there is no way to access the value of these key null entry, if the current thread is not over, The value of these null entry will always have a strong reference chain:
Thread Ref-> thread-> threalocalmap-> Entry-> value
Can never be recycled, causing memory leaks.

Let's see if this will happen.
In fact, the JDK in the design of the Threadlocalmap has taken into account this situation, but also added a number of protection measures, the following is the threadlocalmap of the Getentry method of the source code:

Private Entry Getentry (threadlocal<?> key) {int i = Key.threadlocalhashcode & (table.length-1);
    Entry e = table[i];
    if (e!= null && e.get () = = key) return e;
else return Getentryaftermiss (key, I, E); The source code of the Getentryaftermiss function: Private Entry Getentryaftermiss (threadlocal<?> key, int i, Entry e) {entry[] tab =
     Table
     int len = tab.length;
         while (e!= null) {threadlocal<?> k = E.get ();
         if (k = = key) return e;
         if (k = = null) expungestaleentry (i);
         else i = Nextindex (i, Len);
     e = Tab[i];
 return null;
           The source code of the Expungestaleentry function: private int expungestaleentry (int staleslot) {entry[] tab = table;
           int len = tab.length;
           Expunge entry at Staleslot tab[staleslot].value = null;
           Tab[staleslot] = null;
           size--;
  Rehash until we encounter null         Entry e;
           int i;
                for (i = Nextindex (Staleslot, Len);
                (e = tab[i])!= null;
               i = Nextindex (i, Len)) {threadlocal<?> k = E.get ();
                   if (k = = null) {e.value = null;
                   Tab[i] = null;
               size--;
                   else {int h = k.threadlocalhashcode & (len-1);
                       if (H!= i) {tab[i] = null; Unlike Knuth 6.4 algorithm R, we must scan until//NULL because multiple entries could have
                       n Stale.
                       while (Tab[h]!= null) H = Nextindex (h, Len);
                   TAB[H] = e;
       }} return I; }

Organize the process of Threadlocalmap's getentry function:

The entry e is obtained first from the direct index position of the threadlocal (through the Threadlocal.threadlocalhashcode & (len-1) operation, if E is not null and the key is the same, returns E;
If e is null or the key is inconsistent, it is queried to the next location, if the key in the next position is equal to the key that is currently being queried, the corresponding entry is returned, otherwise the entry of the position is erased if the key value is NULL, otherwise the query continues to the next location
In the process encountered in the key is NULL entry will be erased, then the value within the entry does not have strong reference chain, will naturally be recycled. Careful study of the code can be found that the set operation also has a similar idea, the key is null these entry are deleted to prevent memory leaks.
But the light is not enough, the design of the above depends on a prerequisite: to invoke the Threadlocalmap getentry function or set function. This is of course not possible in any case, so many situations require the user to manually invoke the Threadlocal remove function, manually remove the unwanted threadlocal, and prevent memory leaks. So the JDK suggests that the threadlocal variable be defined as private static, so that the threadlocal life cycle is longer and threadlocal will not be recycled because of threadlocal strong references. You can also ensure that you can access the value of entry at any time according to Threadlocal's weak reference, and then remove it to prevent memory leaks. status problems with the thread pool on the Web server

Web Services in the process of creating threads, the frequent creation of threads on the impact of the system, so many servers have adopted a thread pool to solve the problem caused by the continuous creation of locks, so in the process of using the thread pool, Because the thread is constantly recycled and exploited, threadlocal is also reused in the server, and in use without inventory operations can easily lead to variable pollution. Although for many servers, threadlocal is indeed relative to each thread, each thread will have its own threadlocal. But consider that the server maintains a set of thread pools. Therefore, access by different users may receive the same thread. Therefore, when doing based on theadlocal, it is prudent to avoid the caching of threadlocal variables, causing other threads to access this thread variable, which, if used improperly, can lead to inefficient systems, for example, Assuming that we have access to the system in the threadlocal to add variables not to update and delete, then this saved object becomes an incremental container object, if the traffic is huge, will lead to low JVM memory and frequently trigger the GC,GC at work will replicate data, Frequent triggering of a GC can adversely affect the performance of the system and may result in a memory overflow. problems encountered

public class Contextholder {

    private static threadlocal<usercontext> usercontext = new inheritablethreadlocal <UserContext> ();

    public static UserContext Getusercontext () {
        if (usercontext.get () = null) {
            usercontext.set (new UserContext () );
        }
        return Usercontext.get ();
    }

    public static void SetContext (UserContext context) {
        Usercontext.set (context);
    }

    public static void Clear () {
        usercontext.remove ();
    }
}

If each thread (Access request) does not invoke the clear method at the end of the call, the other thread will contaminate the thread, which is the variable of the other thread.

Reference:
http://qifuguang.me/2015/09/02/[java%e5%b9%b6%e5%8f%91%e5%8c%85%e5%ad%a6%e4%b9%a0%e4%b8%83]%e8%a7%a3%e5%af% 86threadlocal/
http://blog.csdn.net/chichengit/article/details/7994712
http://blog.csdn.net/lufeng20/article/details/24314381
Http://www.importnew.com/22039.html
Http://www.importnew.com/22046.html

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.