之前对TreadLocal有所理解,对原理也有所了解,但一直不深入,重新整理,希望借以加深理解和印象。
在Jdk1.8中,ThreadLocal相关代码主要分为三部分:
- Thread,其中Thread中保存对ThreadLocal.ThreadLocalMap的引用,作为Thread类的default属性;
- ThreadLocal,类似于线程中的T和readLocal.ThreadLocalMap的管理类,提供获取、设置、删除等管理方法;
- ThreadLocal.ThreadLocalMap.ThreadLocal,是ThreadLocal的静态内部内,底层数组结构的维护类,包含扩容、获取等功能,是ThreadLocal的底层核心实现。
1. Thread类
/* 本现场的ThreadLocal. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* 继承自父类来的ThreadLocal.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
通过Thread的构造函数可知默认情况下,inheritableThreadLocals会通过父类的threadLocal初始化,除非特别指明不继承父类的threadLocal。
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
…… ……
// 如果指明要继承,并且父线程的threadLocal不为空
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
// 通过ThreadLocal创建inheritableThreadLocals
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
…… ……
}
小结:每个线程中都有两个属性,即两个ThreadLocalMap,其中一个为线程自己的,一个是初始化线程时,从父线程中的拿来创建的,默认如果父线程有threadLocal,子线程会继承父线程的threadLocal.
2. ThreadLocal类
前文中所说的,ThreadLocal类类似于ThreadLocalMap管理端。ThreadLocal中主要属性和方法如下图:
以下是ThreadLocal中核心方法分析:
// 使用线性探测法进行map的扩容
private final int threadLocalHashCode = nextHashCode();
/**
* 静态全局的存储下一个hash码
*/
private static AtomicInteger nextHashCode =
new AtomicInteger();
/**
* hashCode增量
*/
private static final int HASH_INCREMENT = 0x61c88647;
// 下一个hashCode增加增量
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
/* 重要逻辑,当线程1调用ThreadLocal的get()方法时,首先拿到线程1的threadLocals属性,
* 如果不为空, 通过以当前ThreadLocal为key值获取ThreadLocal中存放的值。这里有点绕,
* 实际相当于,在执行ThreadLocal<String> threadLocal = new ThreadLocal<String>();后,通
* 过get()方法,将拿到线程1中threadLocals通过get()方法以threadLocal为key值的设置的值。
* /
public T get() {
Thread t = Thread.currentThread(); //获取当前线程
ThreadLocalMap map = getMap(t); //获取当前线程的ThreadLocalMap, 即那个属性
if (map != null) { // 如果当前线程存在ThreadLocal
ThreadLocalMap.Entry e = map.getEntry(this); // ThreadLocalMap中以ThreadLocal为key,获取ThreadLocalMap中存放的值
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value; // 转化为正确格式,泛型
return result;
}
}
return setInitialValue();
}
/*
* setInitialValue和set(T value)内部逻辑类似,只是一个传了初始值,一个没有,如果没传初始值,则为null
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread(); // 获取当前线程
ThreadLocalMap map = getMap(t); // 拿到当前线程的threadLocals,
if (map != null)
map.set(this, value); // 在threadLocalMap中设置key为当前ThreadLocal, value为value的值
else
createMap(t, value); // 创建一个ThreadLocalMap,并把引用赋值给当前线程的threadLocals
return value;
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue); //为当前线程创建一个threadMap
}
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) { //这是个静态方法,在Thread中调用,即如果要继承父类的threadLocal,将通过这个房间创建
return new ThreadLocalMap(parentMap);
}
总结:重要的是ThreadLocal中的get和set方法,get方法将最终拿到当前线程的threadLocals,这是一个map,在set的时候以ThreadLocal为key值,实际上是以ThreadLocal的threadLocalHashCode为key值。