众所周知,ThreadLocal类是java提供线程本地变量的工具类。但父线程的本地变量却不能被子线程使用,代码如下:

 1 public static void main(String[] args) {
 2         ThreadLocal<String> threadLocal = new ThreadLocal<>();
 3         threadLocal.set("abc");
 4         System.out.println("父线程:"+threadLocal.get());
 5         Thread t1 = new Thread(new Runnable() {
 6             @Override
 7             public void run() {
 8                 System.out.print("子线程:"+threadLocal.get());
 9             }
10         });
11         t1.start();
12     }

运行结果如下:

至于原因呢,得先了解ThreadLocal存储的变量是怎么存储的。首先,让我们先看看Thread类的源码:在thread类中有声明这么一个成员变量——threadLocals 

ThreadLocal.ThreadLocalMap threadLocals = null;

根据定义可以看出,这是ThreadLocal类里的静态内部类,它的结构是Map结构,以键值对的形式存储值。key值就是当前线程的实例,value值就是当前线程的本地变量。所以线程的本地变量是存在线程实例当中的,而不是存在ThreadLocal中。ThreadLocal只是一个工具类,体现在当ThreadLocal实例调用set()方法时,会将当前线程的threadLocals变量实例化。以下是ThreadLocal类的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);
    }

可以看到,先是获取当前线程的实例,再获取线程的成员变量threadLocals,如果threadLocals已经实例化,就直接以当前线程为key,存储的本地变量为value,存进threadLocals中。所以线程本地变量是存储在线程中的。如果threadLocals未实例化,则调用createMap()方法,该方法会调用ThreadLocalMap的构造方法,初始化一个以当前线程为key,存储的本地变量为value的Map。该Map是类似HashMap的,该兴趣的话可以继续往下看源码,此处不做扩展。

回到最开始的问题,子线程调用ThreadLocal类的get方法,源码如下:

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()方法,因为以子线程实例为key去获取value是空的。setInitialValue()方法源码如下:

private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

可以看到value会默认为null,并为子线程创建一个null的本地变量,最后返回null。

版权声明:本文为doubaozzz原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/doubaozzz/p/12173758.html