ThreadLocal的实现原理是什么,结合源码讲解

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