ThreadLocal thread Local variables and source code analysis

Source: Internet
Author: User
Tags set set

ThreadLocal definition

    • threadlocal resolves the conflicting problem of variable concurrency access by providing a separate copy of the variable for each thread
    • When using threadlocal to maintain variables, Threadlocal provides a separate copy of the variable for each thread that uses the variable, so each thread can independently change its own copy without affecting the copy of the other thread
    • There is a map in the Threadlocal class that stores a copy of the variable for each thread, the key of the element in the map is the thread object, and the value corresponds to the variable copy of the thread.
    • ThreadLocal Self-awareness: You can compare "hotel" to an application, each room is "sub-thread", ThreadLocal is the person who provides service for each "room", each does not conflict with each other and maintains independent
    • JDK1.5 introduction of generics, Threadlocal farewell to the object era into the universal era
    • A container for storing thread-private variables
    • Threadlocal is not intended to solve multi-threaded access shared variables, but instead creates a separate copy of the variable for each thread, providing a way to persist objects and avoid the complexity of parameter passing

ThreadLocal Data structure

1. Class definitions

public class Threadlocal<t>

2. Important internal elements

Private final int threadlocalhashcode = nexthashcode ();p rivate static Atomicinteger Nexthashcode = new Atomicinte GER ();p rivate static final int hash_increment = 0x61c88647; 

3. Constructors

/** ThreadLocal only provides an empty default constructor, which is pure **/public ThreadLocal () {}

ThreadLocal Important methods

1. Set () method

/**  * Sets the current thread's copy of this thread-local variable to the specified value.   * Most subclasses'll has no need to override this method,relying solely on the  * {@link #initialValue} method to SE t the values of thread-locals.  *     Set the value of the thread local variable of the current thread in the current threadlocal  *     Its subclasses do not have to override the method, as long as the overriding InitialValue method sets the initial default value  * @param value The value  to is stored in the current thread's copy of * this        thread-local. Copies the current value to the local variable of the active thread  */public void Set (T V Alue) {    //Gets the current thread    , thread t = thread.currentthread ();    Gets the current thread-held map    threadlocalmap map = getmap (t);    Createmap or set directly    if (map! = null)        //Note that key is this, which refers to the Threadlocal object itself that is currently calling the Set method        Map.set ( This, value);    else        //initializes its threadlocalmap according to the current thread and sets the value Createmap (t, value);}     

2. Get () method

/** * Returns The value in the current thread's copy of this  thread-local variable.   * If the variable have no value for the current thread,it are first initialized to   * The value returned by an invocation Of the {@link #initialValue} method.  *     returns the thread local variable corresponding to the current thread in the current Threadlocak  *     If the current value does not exist, returns the initial default value of the InitialValue method setting  * @return The present thread ' s value of this thread-local  */public t get () {    //Gets the current thread, thread    T = thread.currentthread ();    Gets the current thread-held map    threadlocalmap map = getmap (t);    if (map! = null) {        Threadlocalmap.entry e = map.getentry (this);        if (E! = null) return (T) E.value;}//map is empty or the value is NULL, return the default value return Setinitialvalue ();}    

3. Remove () method

/**  * Removes the current thread ' s value of this thread-local variable.    * IF This thread-local variable was subsequently {@linkplain #get read}   * by the current thread and its value would be rein Itialized  by invoking it * {@link #initialValue} method, unless its value was {@linkplain #set set}  * by the Curre NT thread in the interim.  This could result in multiple invocations   * of the {@code InitialValue} method in the current thread.  *     Remove the private variable corresponding to the current thread in the current threadlocal  *     When the variable is read by the current thread (get), the value will be re-initialized by the InitialValue method unless this period is set  *     This will cause the InitialValue method to be called multiple times by  the current thread * @since 1.5 This method is JDK1.5 new method  */public void Remove () {    // Gets the threadlocalmap that the current thread holds, which shows that the related code in get and set should also be merged into one line    threadlocalmap m = Getmap (Thread.CurrentThread ());    if (m! = null)        //Note is the current Threadlocal object (that is, Threadlocalmap key) removed from Threadlocalmap        m.remove (this);} 

4. Getmap, Createmap method

/**  * Get The map associated with a ThreadLocal. Overridden in  * inheritablethreadlocal.  *  * @param  t The current thread  * @return the map  */Threadlocalmap getmap (thread t) {    return  T.threadlocals;} /**     * Create The map associated with a ThreadLocal. Overridden in     * inheritablethreadlocal.     *     * @param t the current thread     * @param firstvalue value for the initial entry of the map     */void Crea Temap (Thread T, T firstvalue) {      t.threadlocals = new Threadlocalmap (this, firstvalue);}   

5. Nexthashcode method

/**     * Returns the next hash code.   *    /private static int Nexthashcode () {        return nexthashcode.getandadd (hash_increment);    } 

6. InitialValue method

/** * Returns The current thread ' s "initial value" for this thread-local variable. * This method is invoked the first time a thread accesses the variable * with the {@link #get} method, unless the th  Read previously invoked the {@link #set} * method, in which case the <tt>initialValue</tt> method won't be  Invoked for the thread. * Normally, this method was invoked at the most once per thread, but it could be invoked again * in case of subsequent Invocatio  NS of {@link #remove} followed by {@link #get}.         * Returns the initial default value of the current thread in the current threadlocal * The first get operation calls the method unless the set method (that is, the existing value) has been called before * generally the method will only be executed once, but it can occur multiple times, such as: * The Get method was called after the Remove method was called * <p>this implementation simply returns <tt>null</tt>; If the programmer desires * Thread-local variables to a initial value other than <tt>null</tt>, * &lt  ;tt>threadlocal</tt> must is subclassed, and this method overridden.  * Typically, an anonymous inner class would be used.* This method returns null by default, you can override the method (such as inheriting or implementing an anonymous class) * @return The initial value for this thread-local */protected T InitialValue () {return null;} ---------------/** For example, customizing a String type of anonymous threadlocal**/threadlocal<string> stringthreadlocal = new Threadlocal<string>() {@Override protected String InitialValue () {return "I am Roman";}} ;

Threadlocalmap-The secret of thread isolation

    • Threadlocalmap is a special hash table designed specifically for thread-local variables
    • The Threadlocalmap key is Threadlocal,value, which is the value of the variable to be saved
    • Each thread has a private Threadlocalmap object that can hold multiple key-value pairs of different threadlocal as keys
    • Threadlocalmap uses the open address method instead of the list to resolve the conflict, and requires that the capacity must be 2 power

1. Class definitions

Static Class Threadlocalmap

2. Entry

/** * The entries in this hash map extend WeakReference, using * Its main ref field as the key (which are always a * Thr  Eadlocal object). Note that null keys (i.e. entry.get () * = = NULL) mean that the key is no longer referenced and so the * entry can be Expung  Ed from table.  Such entries is referred to * as "stale entries" in the code that follows. * It uses the primary reference domain as its own key (that is, the Threadlocal object) * Because entry inherits from WeakReference, and threadlocal is weakreference encapsulated *!! Key: So entry's key is the weak reference (not entry)!! (I will further elaborate in memory leaks) * When calling the Get method to return null, this means that the key is no longer referenced, so the entry will remove the weak reference from the array: When the JVM finds a weak reference in GC, it will be recovered immediately * The interesting thing is entry There is no linked list structure using Hashmap.entry * Interested readers can first think about how threadlocalmap deals with hash conflicts (explained later) */static class Entry extends WEAKREFERENCE&L T Threadlocal<?>>{/** The value associated with this ThreadLocal. */ Object value; When a threadlocal external strong reference is reclaimed, the THREADLOCALMAP key becomes NULL//Note that key is a Threalocal object, but because the key is weakreference encapsulated, it has a weak reference attribute Entry        (threadlocal<?> K, Object v) {Super(k);    Value = V; }}

3. Important internal elements

/** * The initial capacity-must be a power of. *  capacity must be power 2 times, serving the hash algorithm */private static final int initial_capacity =/** * The table, resized as necessary. Table. Length must always be a power of. *  The underlying implementation is also a Entry array */private entry[] table;/** * The number of entries in the  table.  * Array already has the number of elements  */private int size = 0;/**  * The next size value at which to resize.  * Threshold value, default to 0  */private int threshold;//defaults to 0  

4. Constructors

/** * Construct A new map initially containing (Firstkey, firstvalue).  * Threadlocalmaps is constructed lazily, so we had create * one when we had at least one entry to put in it. * Default constructor, contains a key-value pair: A threadlocal type of key, an arbitrary type of value * Createmap method will be used directly to complete the Threadlocalmap instantiation and key-value pair storage */ Th    Readlocalmap (ThreadLocal Firstkey, Object firstvalue) {table = new  entry[initial_capacity]; The computed array subscript is consistent with HashMap's index = Key.hashcode () & (Cap-1) (that is, the modulo operation is optimized) int i = Firstkey.threadlocalhashcode & (in    Itial_capacity-1 );    Fills an array with the subscript at the specified index table[i] = new  Entry (Firstkey, firstvalue);    size = 1 ; Setthreshold (initial_capacity)////default threshold is 32/3 approximately equals 10.6667 }/** * Set The resize threshold to maintain at worst a 2/3 lo Ad factor. * Take Len Two-thirds instead of HashMap 0.75 */private void setthreshold (int  len) {threshold = Len * 2/3 ;}   

5. Threadlocalmap some important methods

1) Set method

/** * Set The value associated with key. * Store key value pairs, it is interesting to note that entry is not a linked list, which means that the threadlocalmap is just an array * its resolution of the conflict (or hash optimization) is the key to the magical 0x61c88647 * if you encounter an expired slot, it will occupy the expiration slot (it involves displacement and Slot cleanup operation) * When the cleanup successfully reaches the threshold at the same time, it needs to expand * @param key The thread local object * @param value the value to be set */private voidSet (ThreadLocal key, Object value) {entry[] tab =table; int len = tab.length;//array capacity//computed array subscript with HashMap index = Key.hashcode () & (cap-1) consistent (i.e. modulo op optimized) int i = Key.thr    Eadlocalhashcode & (Len-1);        for (Entry e = tab[i]; e = null; e = Tab[i = Nextindex (i, Len)]) {ThreadLocal k = e.get (); If key already exists, replace the value if (k = = key) {e.value = value; return;}//If the current slot is an expired slot, clear and occupy the expiration slot if (k = = null) {R Eplacestaleentry (key, value, I); return;}//Continue until you find the key equal or the first expiration slot } Tab[i] = new Entry (key, value); int sz = + +size; To expand the amount of//cleansomeslots to be processed is an existing number of elements if (!cleansomeslots (i, SZ) && sz >= threshold) rehash ();} /** * Increment i modulo len. No longer than 1 */private static int nextindex (int i, int len) {return ((i + 1 < len)} (i + 1:0);}  

2) Remove method

/**  * Remove the entry for key.  *     When the element is found, the main two cleaning operations  *         1. Set key (ThreadLocal) to null  *         2. The current slot becomes an expired slot, Therefore, to clear the Entry element stored in the current slot (primarily to avoid memory leaks)  */private void Remove (ThreadLocal key) {    entry[] tab = table;    int len = tab.length;    int i = Key.threadlocalhashcode & (len-1);    for (Entry e = tab[i];e! = Null;e = Tab[i = Nextindex (i, Len)]) {        if (e.get () = = key) {e.clear ();//will set key to null-this.referent = null expungestaleentry (i);//clear expired element return;       }}}

Collision resolution with the magical 0x61c88647

    • The witty reader must have found that Threadlocalmap did not use a linked list or red-black tree to solve the problem of hash conflicts, but simply using arrays to maintain the entire hash table, then how to ensure that the heavy weight of the hash is a big test
    • Threadlocalmap solves this problem by combining three ingenious designs:
      1. Entry key is designed as a weak reference, so key can be GC (i.e., fail fast) at any time, as much as possible in the face of empty slots
      2. (When a single threadlocal) when encountering a collision, solve the conflict problem by the open address method of linear detection
      3. (When multiple threadlocal) introduces magical 0x61c88647, enhances its hashing, greatly reduces the collision probability
    • The reason why use this value without summing up, I think it may be related to the nearest empty slot (jump lookup than the self-increment 1 to find empty slots may be more effective, because there is more optional space spreading out), but also with its good hash of the
/** * The difference between successively generated hash codes-turns * Implicit sequential thread-local IDs into Near-op timally spread * Multiplicative hash values for power-of-two-sized tables. * in  order to allow the hash code to be evenly distributed in the 2 N-square array */private static final int hash_increment = 0x61c88647;/** * Returns the next hash code. *  each threadlocal hashcode each cumulative hash_increment */private static int Nexthashcode () {    //the previous ID + our Magic number    return nexthashcode.getandadd (hash_increment);}  

The implementation mechanism of ThreadLocal

    • Each thread has a Threadlocalmap object, which is threadlocal.threadlocalmap threadlocals = null
    • Each Threadlocal object has a unique hashcode generated when created, that is, Nexthashcode (), which determines where the slot is positioned by the modulo
    • Accesses the value of a threadlocal variable, that is, to find the corresponding key-value pair in the Threadlocalmap, which is the key-value pair for the Threadlocal key
    • Since a threadlocalmap can have many threadlocal, it can be deduced that a thread can have multiple threadlocal (or a key-value pair that has multiple different threadlocal as keys)
You can define multiple threadlocal, each of which has its own private, generic threadlocal//such as thread A can have the following three Threadlocal objects as keythreadlocal<string> stringthreadlocal = new threadlocal<string>(); threadlocal<object> objectthreadlocal = new threadlocal<object>(); threadlocal<integer> intthreadlocal = new threadlocal<integer> (); 

Ps:

Follow-up will discuss with you some memory leaks and threadlocal practical application problems, please advise!! ************

ThreadLocal thread Local variables and source code analysis

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.