ThreadLocal 是 Java 中的一个类,它提供了线程本地变量。这些变量不同于它们的正常变量,因为每一个访问变量的线程都有其自己的独立初始化的变量副本。ThreadLocal 实例通常用作保存线程相关的数据,如用户ID、事务信息等。每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
下面我们来探讨 ThreadLocal 的实现原理,并结合源码进行解释。
实现原理
ThreadLocal 的实现主要依赖于 ThreadLocalMap 这个内部类。每个 Thread 对象都持有一个 ThreadLocalMap 的引用,这个 ThreadLocalMap 用来存储 ThreadLocal 对象与具体值的映射关系。当我们在某个线程中调用 ThreadLocal 的 set 方法时,实际上是往当前线程的 ThreadLocalMap 中存入数据;当我们调用 get 方法时,实际上是从当前线程的 ThreadLocalMap 中取出数据。
由于每个线程都有自己独立的 ThreadLocalMap,因此不同线程中的 ThreadLocal 变量是隔离的,互不影响。
源码讲解
1. ThreadLocalMap
ThreadLocalMap 是一个定制的 HashMap,用于存储 ThreadLocal 对象与值的映射关系。它的键是 ThreadLocal 的弱引用,值则是存储的线程局部变量。
2. set 方法
当我们调用 ThreadLocal 的 set 方法时,会调用 ThreadLocalMap 的 set 方法来存储数据。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
这里首先获取当前线程,然后获取当前线程的 ThreadLocalMap。如果 ThreadLocalMap 不存在,则调用 createMap 方法创建它。
3. get 方法
当我们调用 ThreadLocal 的 get 方法时,也是从当前线程的 ThreadLocalMap 中取出数据。
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 不存在或者其中没有对应的键值对,那么会调用 setInitialValue 方法来设置初始值。
4. remove 方法
当我们调用 ThreadLocal 的 remove 方法时,会从当前线程的 ThreadLocalMap 中移除对应的键值对。
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null) m.remove(this);
}
总结
通过上面的源码分析,我们可以看到 ThreadLocal 的实现主要依赖于 ThreadLocalMap 这个内部类。每个线程都有一个独立的 ThreadLocalMap,用来存储 ThreadLocal 对象与值的映射关系。这样,不同线程中的 ThreadLocal 变量就被隔离开来,实现了线程局部变量的效果。