关系概览图
晒一下源码
Thread类
package java.lang;
public class Thread implements Runnable {
// Thread类中维护了 ThreadLocalMap 变量,修饰符默认为 protected
ThreadLocal.ThreadLocalMap threadLocals = null;
}
ThreadLocal类、ThreadLocalMap类
package java.lang;
public class ThreadLocal<T> {
// 静态内部类 ThreadLocalMap
static class ThreadLocalMap {
// 静态内部类 Entry,且其继承了弱引用,key值存入了弱引用对象中
static class Entry extends WeakReference<ThreadLocal<?>> {
// value 值,我们通过 ThreadLocal 存储的值的位置,就是这个 value 变量
Object value;
Entry(ThreadLocal<?> k, Object v) {
// key 值直接赋值给了父类,其为弱引用
super(k);
// value 在本对象中,为强引用
value = v;
}
}
// Entry 数组,可以存储多个 value
private Entry[] table;
// ThreadLocalMap 构造方法
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
// 构建一个Entry对象,存储数据,并放入table数组中
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
}
// 设置键、值
public void set(T value) {
// 获取当前线程
Thread t = Thread.currentThread();
// 获取线程类内维护的 ThreadLocalMap 变量:threadLocals,第一次为 null
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
// 第一次为 null,创建 ThreadLocalMap
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
// 直接返回 Thread 类中 threadLocals 变量,第一次默认为null
return t.threadLocals;
}
// 创建 ThreadLocalMap
void createMap(Thread t, T firstValue) {
// 调用构造方法创建 ThreadLocalMap,将构建的对象直接赋值给当前线程的 threadLocals 变量
// 在上面的构造方法中,可知 键值对 会被构建为Entry对象,存入 Entry数组变量 table 中
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
}
通过上述代码可知(需结合代码注释理解):
- Thread类和ThreadLocal类的包名相同,都是
java.lang,而Thread中的threadLocals 变量修饰为protected,所以我们在业务代码中不能通过Thread直接去操作ThreadLocalMap,此处是故意设计为只能通过ThreadLocal去操作线程本地变量。 - 跟踪上述代码中ThreadLocal类的set方法,可以知道:
- 我们存入的
key-value对,实际最终会被构建为Entry对象,并存入ThreadLocalMap类中维护的Entry数组:table变量中; - 通过ThreadLocal对象调用set、get方法操作线程本地变量时,其实是对当前线程中的变量进行操作,并基于此实现了线程之间的数据隔离;
- 我们存入的
key-value对,key直接赋值给了父类(弱引用)的变量,value在Entry对象中存储,顾其key为弱引用、value为强引用。
- 我们存入的
扩展
我们存入的key-value对,最终是以Map结构存储的吗?
ThreadLocal真的很容易导致内存泄露吗?怎么使用会导致其内存泄露
举一个ThreadLocal的场景应用
下期见…