Interpretation of ThreadLocal source code
1、 Introduce
public class Thread implements Runnable {
/* 前面略 */
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/* 后面略 */
}
First of all, we can see that there is an attribute threadlocals in the thread. Its type is threadlocalmap, and its encapsulation type is default (indicating that it can only be seen in the package). JDK introduces it this way: the ThreadLocal value related to this thread, and the mapping is maintained by the ThreadLocal class. What do you mean? Let's see what threadlocalmap is!
public class ThreadLocal<T> {
/* 前面略 */
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference,using
* its main ref field 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 ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k,Object v) {
super(k);
value = v;
}
}
/* 后面略 */
}
}
It can be seen from the class definition that ThreadLocal supports generics, and threadlocalmap is an internal class of ThreadLocal, The encapsulation type is also default (indicating that it can only be seen in the package). This is how JDK introduces it: threadlocalmap is a custom hash map, which is only suitable for maintaining thread local values. In addition, in order to control the storage capacity and avoid memory leakage, the hash table entries use weak references as keys (the life cycle of weakly referenced objects is recycled until the next garbage collection). Threadlocalmap uses the static internal class entry (which can be compared with the entry in the map) to store the actual key and value.
From the above introduction, we can roughly think that ThreadLocal is a thread related class used to store and maintain thread local values.
2、 Interpretation of set (t value) method
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this,value);
else
createMap(t,value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t,T firstValue) {
t.threadLocals = new ThreadLocalMap(this,firstValue);
}
You can see that the set (t value) method is very simple. It is to maintain the threadlocals attribute of thread. If the attribute does not exist, create one with the current ThreadLocal instance as the key; If this attribute exists, it will be assigned directly.
3、 Interpretation of 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();
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this,value);
return value;
}
protected T initialValue() {
return null;
}
The method of get () is also very simple. It is to get the value from the threadlocals property of thread. If it cannot be obtained, assign the value of initialvalue () to the threadlocals property of thread and return it. The initialvalue () method is a protected method. It returns null by default. We can override it when creating ThreadLocal to represent the default values of all threads.
// java8 的方式
ThreadLocal<Boolean> threadLocal1 = ThreadLocal.withInitial(() -> false);
//
ThreadLocal<Boolean> threadLocal2 = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
}
};