上网查看了很多篇ThreadLocal的原理的博客,上来都是文字一大堆,费劲看了半天,大脑中也没有一个模型,想着要是能够有一张图明确表示出来ThreadLocal的设计该多好,所以就自己看了源码,画了一张图出来,立刻清晰不少。
根据源码代码理清ThreadLocal结构
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();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
ThreadLocal.ThreadLocalMap threadLocals = null;
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
通过上面的代码可以看出来,在每个线程里面都保存了ThreadLocalMap,而ThreaLocalMap里面又存储了以ThreadLocal为键值的Entry数组。
用一张图来表示更清楚
ThreatLocal的Set步骤
先看ThreadLocal的set方法,我们看一下ThreatLocal具体是怎么操作的
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);
}
通过上面的代码可以看出来ThreadLocal的存储
1、 获取当前线程
2、 获取到当前线程中的ThreadLocalMap
3、 如果获取到的ThreadLocalMap不为null,就以当前ThreadLocal对象为键,以要插入的值为值,ThreadMapLocalMap中。
4、 如果获取的的ThreadLocalMap为null,则创建一个ThreadLocalMap对象
ThreadLocal的Get步骤
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);
else
createMap(t, value);
return value;
}
通过上面的代码可以看出来ThreadLocal的Get步骤为
1、 获取当前线程
2、 根据当前线程获取线程中的ThreadLocalMap
3、 如果获取到的ThreadLocalMap不为null,则以当前ThreadLocal为键,获取存储在ThreadLocalMap中的值并返回
4、 如果获取到的ThreadLocalMap为null,则创建一个以当前对象为键的对象,以ThreadLocal设置的初始值为值,存入ThreadLocalMap中,然后返回。
ThreaLocal中的初始值设置
protected T initialValue() {
return null;
}
上面这个initalValue方法是在创建ThreadLocalMap时候的value值的默认初始值,代码中默认返回的是null,我们可以通过自己在代码中自己设计值。