Threadlocal implementation principle, SPRINGMVC single thread safety is implemented with this

Source: Internet
Author: User
Tags constructor garbage collection hash int size modulus rehash static class thread class
1. Background

Threadlocal source Interpretation, online has been flooding, mostly shallow, and even some basic principles are said to have a problem, including Baidu search out of the first high-traffic blog, said threadlocal inside there is a map, the key for the thread object, too misleading people.

Threadlocal is ideal for programmers interested in Java multithreaded programming as a category to read, for two reasons: Add Comment Source code is also only seven hundred or eight hundred lines. The structure is clear and the code is concise.

This paper focuses on the nested inner class threadlocalmap in Threadlocal, and introduces the Threadlocal API in brief.
Read Threadlocal source code, do not read the implementation of THREADLOCALMAP, and have not seen much difference. 2. Two questions

Answer two questions First:

What is threadlocal.
The Threadlocal class can be understood as the thread-local variable as its name implies. That is, if you define a threadlocal, each thread is thread-isolated to read and write to this threadlocal, and will not affect each other. It provides a mechanism for threading the variable data through each thread with its own independent copy.

It is how the idea of the general realization.
The thread class has an instance variable threadlocals of type Threadlocal.threadlocalmap, which means that each thread has its own threadlocalmap. Threadlocalmap has its own independent implementation and can simply view its key as threadlocal,value as the value placed in the code (in fact, the key is not the threadlocal itself, but a weak reference to it). Each thread in a threadlocal to the value of the time, will go to their own threadlocalmap, read also a threadlocal as a reference, in their own map to find the corresponding key, thus realizing the thread isolation. 3. Threadlocal's API

Threadlocal API actually not much good introduction, these API introduction online already Rotten Street.
4. Threadlocalmap's source code implementation

Threadlocalmap Source code Realization, is we read threadlocal source really to understand. Look at the craftsmanship of the master Doug Lea and Joshua Bloch.

THREADLOCALMAP provides an efficient implementation for threadlocal customization, and comes with a garbage cleanup mechanism based on weak references.
Here's a little bit of reading from the basic structure. 4.1 Storage Structure

Since it is a map (be careful not to confuse with Java.util.map, this refers to the conceptual map), of course, have to have their own key and value, the above answer to the question 2 has also been mentioned, we can simply consider it as the key to Threadlocal,value to actually put the value. It is said to be simple, because in fact threadlocal is stored in the weak reference of threadlocal. Let's take a look at how the nodes in Threadlocalmap are defined.

Static Class Entry extends Weakreference<java.lang.threadlocal<?>> {
    //to ThreadLocal the value
    actually plugged into Object value;

    Entry (java.lang.threadlocal<?> K, Object v) {
        super (k);
        Value = V;
    }
}

Entry is the node defined in Threadlocalmap, which inherits the WeakReference class and defines a value of type object that holds values that are plugged into the threadlocal. 4.2 Why weak references

Read here, if you do not ask why this is the definition of the form, why use a weak reference, is equal to not read the source.
Because if you use the normal Key-value form to define the storage structure, essentially it will cause the node's life cycle and the line Chengqiang binding, as long as the thread is not destroyed, then the node in GC analysis has been in the state of the status, no way to be recycled, and the program itself can not determine whether to clean up the node. A weak reference is a third file in Java that is referenced in four files, weaker than soft references, and if an object does not have a strong reference chain to reach, then it is generally not possible to live the next GC. When a threadlocal has no strong reference, then as it is garbage collected, the corresponding entry key value in the Threadlocalmap will be invalidated, which facilitates the garbage cleanup of Threadlocalmap itself. 4.3 class member variables and corresponding methods

/**
 * Initial capacity, must be a power of 2 */
private static final int initial_capacity = +;

/**
 * Entry table, size must be 2 power
 */
private entry[] table;

/**
 * Table Entry number *
 /
private int size = 0;

/**
 * Reassign table size threshold, default is 0
 */

As you can see, Threadlocalmap maintains a Entry table or entry array, and requires that the size of the table must be a power of 2, while recording the number of entry in the table and the next threshold to expand.
Obviously there is a problem here, why it must be a power of 2. Very well, but I can't answer it at the moment, take the question and read it down.

/**
 * Set resize threshold to maintain the worst 2/3 load factor *
/private void setthreshold (int len) {
    threshold = Len * 2/3;
}

/**
 * The next index of the ring meaning */
private static int nextindex (int i, int len) {
    return ((i + 1 < len), i + 1:0);  c10/>}

/**
 * Last index of ring meaning */
private static int previndex (int i, int len) {
    return (i-1 >= 0) ? I-1: len-1);
}

Threadlocal need to maintain a load factor of the worst 2/3, for the load factor believe should not be unfamiliar, in the hashmap there is this concept.
Threadlocal has two methods for getting a previous/Next index, note that this is actually the previous and next in the ring sense.

Because Threadlocalmap uses linear probing to resolve hash collisions, the entry[] array is actually in the program logic as a ring.
For open addressing, linear detection and other content, you can refer to the online information or TAOCP ("Computer Programming Art") in the third volume of 6.4 chapters.

So far, we have been able to outline the internal storage structure of THREADLOCALMAP. Here is the schematic diagram I drew. Dashed lines represent weak references, and solid lines represent strong references.

Threadlocalmap maintains the entry ring array, the logical key of the element entry in the array is a Threadlocal object (which is actually a weak reference to the Threadlocal object). Value is the values that the thread actually plugs into the THREADLOACL variable in the code. 4.4 Constructors

Okay, let's take a look at one of the Threadlocalmap constructors.

/**
 * Constructs a map that contains Firstkey and firstvalue.
 * Threadlocalmap is an inert construct, so it is only constructed when at least one element is placed inside.
 */
Threadlocalmap (java.lang.threadlocal<?> Firstkey, Object firstvalue) {
    //Initialize table array
    table = new entry[ Initial_capacity];
    Using Firstkey's Threadlocalhashcode and initial size 16 modulo to get the hash value
    int i = Firstkey.threadlocalhashcode & (initial_capacity-1); c8/>//Initialize the node
    table[i] = new Entry (Firstkey, firstvalue);
    Set the node table size to 1 sizes
    = 1;
    Set the expansion threshold
    Setthreshold (initial_capacity);
}

This constructor may be called indirectly at set and get to initialize the thread's threadlocalmap. 4.5 hash Function

Take a look at the int i = Firstkey.threadlocalhashcode & (initial_capacity-1) in the constructor above, this line of code.

The Threadlocal class has a final decorated threadlocalhashcode of type int, which is generated when the threadlocal is constructed, equivalent to a threadlocal ID, and its value is derived from

 /* * Generate hash code gap for this magic number, you can let the generated value or threadlocal ID more evenly distributed in a power-sized array of 2.
 */
private static final int hash_increment = 0x61c88647;

private static int Nexthashcode () {
    return nexthashcode.getandadd (hash_increment);
}

As can be seen, it is on the basis of the last constructed threadlocal Id/threadlocalhashcode, plus a magic number 0x61c88647. The selection of this magic number is related to the Fibonacci hash, and the 0x61c88647 corresponds to a decimal of 1640531527. The multiplier of the Fibonacci hash can be used (long) ((1L <<) * (MATH.SQRT (5)-1)) to get 2654435769, if the value is converted to a signed int, you will get-1640531527. Other words
(1L <<)-(Long) ((1L <<) * (MATH.SQRT (5)-1) The result is 1640531527 is 0x61c88647. Through theory and practice, when we use 0x61c88647 as the magic number accumulation for each threadlocal to assign their own ID that is threadlocalhashcode and 2 of the power to take the model, the resulting distribution is very uniform.
The threadlocalmap uses a linear detection method, and the benefit of uniform distribution is that it quickly detects the next available slot that is adjacent, thus guaranteeing efficiency. This answers the question of why the size should be a power of 2. In order to optimize efficiency.

For & (Initial_capacity-1), believe that there have been algorithmic competition experience or read the source of a lot of programmers, a look on the power as a modulus of 2, you can use & (2^n-1) to replace the%2^n, bit operation than modulus efficiency is much higher. As for why, because of the 2^n modulus, as long as not the low-n-bit contribution to the result is obviously 0, will affect the result can only be low n-bit.

Can be said in the threadlocalmap, shaped like Key.threadlocalhashcode & (Table.length-1) (where key is a threadlocal instance) is essentially a hash of a threadlocal instance, except that it is not pumped into a common function in the source code implementation. 4.6 Getentry Method

This method is called directly by the threadlocal get method to get the value stored by a threadlocal in the map.

Private Entry Getentry (threadlocal<?> key) {////////based on the ID of this ThreadLocal key, which is the hash value int i = Key.threadlocalhash
    Code & (Table.length-1);
    Entry e = table[i];
    If the corresponding entry exists and is not invalidated and the weak reference points to a threadlocal that is key, the hit returns if (E! = null && e.get () = = key) {return e;
        } else {//Because a linear probe is used, it is possible to find the target entry in the future something else.
    Return Getentryaftermiss (key, I, E); }/* * Call this method when Getentry is not directly hit */private Entry Getentryaftermiss (threadlocal<?> key, int i, Entry e) {Ent
    ry[] tab = table;
   
    
    int len = tab.length;
    Based on the linear detection method, it is continuously detected until an empty entry is encountered.
        while (E! = null) {threadlocal<?> k = E.get ();
        Locate target if (k = = key) {return e; } if (k = = null) {///the entry corresponding threadlocal has been reclaimed, calling Expungestaleentry to clean the invalid entry expungestal
        Eentry (i);
        } else {//ring meaning go back i = Nextindex (i, Len);
    } e = Tab[i]; } returnNull /** * This function is the core cleanup function in threadlocal, it does the simple thing: * is to start the traversal from the Staleslot, the invalid (weak reference point to the object is recycled) cleanup, that is, the value in the corresponding entry is NULL,
 Table[i that points to this entry] is set to null until the empty entry is swept.
 * In addition, non-empty entry will be rehash in the process. * It can be said that the function is to start cleaning up the slots in the contiguous segment from Staleslot (break strong references, rehash slots, etc.) */private int expungestaleentry (int staleslot) {entry[] t
    AB = table;

    int len = tab.length;
    Because the entry corresponding threadlocal has been reclaimed, value is set to NULL, and the strong reference Tab[staleslot].value = null is explicitly broken;
    Explicitly set the entry to NULL for garbage collection tab[staleslot] = null;

    size--;
    Entry e;
    int i; for (i = Nextindex (Staleslot, Len); (e = Tab[i])! = NULL;
        i = Nextindex (i, Len)) {threadlocal<?> k = E.get ();
            Clears the entry if (k = = null) {E.value = null) for which the corresponding threadlocal has been reclaimed;
            Tab[i] = null;
        size--;
             } else {/* * for cases that have not yet been recycled, you need to do a rehash.
             * * If the corresponding threadlocal ID to len modulo the index h is not the current position i, * then linearly from the H to detect the first empty slot, the current entry to move over.
   */         int h = k.threadlocalhashcode & (len-1);
                
                if (h! = i) {tab[i] = null; /* * In the original code here is a comment that is worth mentioning, the original comment is as follows: * * Unlike Knuth 6.4 algorithm R, we must s
                 can until * NULL because multiple entries could have been stale. * This paragraph mentions the r algorithm in chapter 6.4 (hash) * of Knuth Gartner's book TAOCP (computer Programming Art).
                 The R algorithm describes how to remove an element from a hash table that uses a linear probe. * The R algorithm maintains an index of the last deleted element, and when the hash value of a entry is scanned in a non-empty contiguous segment, the indexed * has not been traversed to

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.