ThreadLocal
2022年1月12日约 2876 字大约 10 分钟
ThreadLocal

- Thread类中,有个ThreadLocal.ThreadLocalMap 的成员变量。
- ThreadLocalMap内部维护了Entry数组,每个Entry代表一个完整的对象,key是ThreadLocal本身,value是ThreadLocal的泛型对象值。
````
public class Thread implements Runnable {
// ThreadLocal.ThreadLocalMap是Thread的属性
ThreadLocal.ThreadLocalMap threadLocals = null;
}
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
//Entry数组
private Entry[] table;
// ThreadLocalMap的构造器,ThreadLocal作为key
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
}
public void set(T value) {
Thread t = Thread.currentThread(); //获取当前线程t
ThreadLocalMap map = getMap(t); //根据当前线程获取到ThreadLocalMap
if (map != null) //如果获取的ThreadLocalMap对象不为空
map.set(this, value); //K,V设置到ThreadLocalMap中
else
createMap(t, value); //创建一个新的ThreadLocalMap
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals; //返回Thread对象的ThreadLocalMap属性
}
void createMap(Thread t, T firstValue) { //调用ThreadLocalMap的构造函数
t.threadLocals = new ThreadLocalMap(this, firstValue); this表示当前类ThreadLocal
}
}
public T get() {
Thread t = Thread.currentThread();//获取当前线程t
ThreadLocalMap map = getMap(t);//根据当前线程获取到ThreadLocalMap
if (map != null) { //如果获取的ThreadLocalMap对象不为空
//由this(即ThreadLoca对象)得到对应的Value,即ThreadLocal的泛型值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue(); //初始化threadLocals成员变量的值
}
private T setInitialValue() {
T value = initialValue(); //初始化value的值
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); //以当前线程为key,获取threadLocals成员变量,它是一个ThreadLocalMap
if (map != null)
map.set(this, value); //K,V设置到ThreadLocalMap中
else
createMap(t, value); //实例化threadLocals成员变量
return value;
}
实现原理
- Thread线程类有一个类型为ThreadLocal.ThreadLocalMap的实例变量threadLocals,即每个线程都有一个属于自己的ThreadLocalMap。
- ThreadLocalMap内部维护着Entry数组,每个Entry代表一个完整的对象,key是ThreadLocal本身,value是ThreadLocal的泛型值。
- 并发多线程场景下,每个线程Thread,在往ThreadLocal里设置值的时候,都是往自己的ThreadLocalMap里存,读也是以某个ThreadLocal作为引用,在自己的map里找对应的key,从而可以实现了线程隔离。
public class TianLuoThreadLocalTest {
private static final ThreadLocal<String> threadLocal1 = new ThreadLocal<>();
private static final ThreadLocal<String> threadLocal2 = new ThreadLocal<>();
}
一个使用类,有两个共享变量,也就是说用了两个ThreadLocal成员变量的话。如果用线程id作为ThreadLocalMap的key,怎么区分哪个ThreadLocal成员变量呢?因此还是需要使用ThreadLocal作为Key来使用。每个ThreadLocal对象,都可以由threadLocalHashCode属性唯一区分的,每一个ThreadLocal对象都可以由这个对象的名字唯一区分(下面的例子)。看下ThreadLocal代码:
public class ThreadLocal<T> {
private final int threadLocalHashCode = nextHashCode();
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
}
public class TianLuoThreadLocalTest {
public static void main(String[] args) {
Thread t = new Thread(new Runnable(){
public void run(){
ThreadLocal<TianLuoDTO> threadLocal1 = new ThreadLocal<>();
threadLocal1.set(new TianLuoDTO("Hello 七度"));
System.out.println(threadLocal1.get());
ThreadLocal<TianLuoDTO> threadLocal2 = new ThreadLocal<>();
threadLocal2.set(new TianLuoDTO("你好:ccc"));
System.out.println(threadLocal2.get());
}});
t.start();
}
}
// 运行结果
TianLuoDTO{name='Hello 七度'}
TianLuoDTO{name='你好:ccc'}





贡献者
wangjialin