ThreadLocal class (TL substitution) mainly provides local variables of thread scope for applications, that is, the values of these variables are only valid in the threads they store. TL object is not a local variable, it is more like a guide.
When a thread is still running and the ThreadLocal object is accessible, the thread will hold an implicit reference to the ThreadLocal object. ThreadLocal object is reclaimed when the thread is reclaimed. A thread can have multiple TL objects.
Each Thread maintains a ThreadLocalMap class, the thread local variable container, which is where the real thread local variable is stored and corresponds to the current thread one by one. The main purpose of TL is to access the data in the map. On the one hand, it acts as the key of variables. On the other hand, it optimizes the access of local variable containers according to the TL's own property threadLocalHashCode. The overall result is that when a thread that does not create the TL object accesses the object, it will get null. When the thread that creates the TL object accesses the object, it can quickly find the change according to TL. Quantity. Note: TheadLocalHashCode is dynamically controlled by Atomic Integer type, that is, there will not be the same TL object as threadLocalHashCode globally.
Next, through the code, specific analysis of the above process.
- Let's first look at the class structure of TL
TL supports generics and constructors have no special operations.
HashCode has a globally unique property threadLocalHashCode for optimizing access.
private final int threadLocalHashCode = nextHashCode();
private static AtomicInteger nextHashCode =
new AtomicInteger();
private static final int HASH_INCREMENT = 0x61c88647;
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
- Storage of data
public void set(T value) {
//Get the current thread
Thread t = Thread.currentThread();
//Get the local variable container for the current thread
ThreadLocalMap map = getMap(t);
//If the container is not empty, set it -- refer to AA1
if (map != null)
map.set(this, value);
else
//Containers are empty, create containers
createMap(t, value);
}
- AA1, only core code analysis
private void set(ThreadLocal key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
//Cyclic ellipsis, mainly key value filtering, and repetition returns null
//Make it accessible by the same TL object of this thread.
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
- Read variables
public T get() {
//Get the current thread
Thread t = Thread.currentThread();
//Get the local variable container for the current thread
ThreadLocalMap map = getMap(t);
if (map != null) {
//If the container is not empty, the local variable container is obtained from the TL object, and the variables are further obtained. Reference AA2
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
- AA2, Get the key-value pair of the corresponding TL object from the container
private Entry getEntry(ThreadLocal key) {
//Getting key-value pair positions based on unique attributes
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
//If there is this TL in the container and the key has value
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
ThreadLocalMap is a custom hashMap that only stores thread local variables. Specific source code is no longer analyzed.
To sum up, ThreadLocal plays three main roles: 1 - access an entry to thread local variables; 2 - act as a key to correspond to a stored local variable; 3 - optimize the way thread local variable container accesses data according to its global unique property.