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
变量就被隔离开来,实现了线程局部变量的效果。