ThreadLocal(线程本地变量),作用是让每个线程都维护一份独立的变量副本,解决了变量并发访问冲突的问题。表面上看,变量是存储在ThreadLocal里面的,实则不然:
1. ThreadLocal只是个“工具类”,对外暴露了get、set、remove接口;
2. 内部实现:变量其实是保存在当前线程Thread类里,准确来说是保存在Thread类中由ThreadLocal实现的ThreadLocal.ThreadLocalMap成员变量里;
set方法
public void set(T value) {
// 获取当前线程
Thread t = Thread.currentThread();
// 尝试获取当前线程内部的ThreadLocalMap
ThreadLocalMap map = getMap(t);
// map不为空,就正常set值
if (map != null)
map.set(this, value);
else
// 否则就初始化Map
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
// 可以看出,ThreadLocalMap是存储在线程对象里的
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
// new个ThreadLocalMap,key和value分别为当前ThreadLocal对象已经传入的值
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
get方法
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
// 如果map不为空,就尝试获取;
if (map != null) {
// 以当前ThreadLocal对象为key,获取对应的值
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();
// 以下过程和set方法一样
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
// 这里可以看出,这个方法可以由子类实现,默认返回null
protected T initialValue() {
return null;
}
remove方法
public void remove() {
// 尝试获取ThreadLocalMap
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
// map不为空,则移除key为当前ThreadLocal对象的Entry
m.remove(this);
}
小结论:ThreadLocalMap存储在Thread对象里,但却是在ThreadLocal对象里进行初始化,ThreadLocal对外暴露的接口实际上都是交给ThreadLocalMap进行处理,所以ThreadLocalMap是核心部分。
参考: