JDK源码:InheritableThreadLocal实现原理

一.ThreadLocal

    Thread中有一个ThreadLocalMap类型的属性,threadLocals:

​ThreadLocal.ThreadLocalMap threadLocals = null;


    ThreadLocal的 set() 方法:拿到当前线程的 threadLocals,然后往其中塞值,key是ThreadLocal本身,value是塞入的值

取出Map的时候,如果为空,则初始化Map。

    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 getMap(Thread t) {
        return t.threadLocals;
    }
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

    ThreadLocal的 get() 方法:从线程中拿出threadLocals,如果不为空,从map中拿出键值对。如果Map为空或者没有拿到值,则直接返回null。

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);// getMap方法,被InheritableThreadLocal重写了
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();// map为空 or 没有取到值
    }
    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;
    }
    protected T initialValue() {
        return null;
    }
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==


二.InheritableThreadLocal

    首先看一个例子:

public class ThreadLocalParentSon {
       //public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
       public static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<Integer>();
       static class MyThread extends Thread{
            @Override
            public void run(){
                System.out.println("Son Thread = " + threadLocal.get());
            }
       }
       public static void main(String[] args) {
             threadLocal.set(new Integer(127));// 当前线程设置值
             Thread thread = new MyThread();
             thread.start();
             System.out.println("Main Tread = " + threadLocal.get());
       }
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

    没有使用 InheritableThreadLocal 之前的输出结果:

Main Tread = 127
Son Thread = null
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

    使用 InheritableThreadLocal 之后的输出结果:

Main Tread = 127
Son Thread = 127
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

    透过现象看本质,分析子线程能够从父线程那里继承的值的原理:

    看看 InheritableThreadLocal 的源码:重写了ThreadLocal的3个方法

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
    protected T childValue(T parentValue) {
        return parentValue;
    }
    ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }
    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

    在Thread中,还有另外一个类型为ThreadLocalMap类型的属性,inheritableThreadLocals。

ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

    重写的 getMap() 和 createMap() 方法,把之前对 threadLocals 的操作,换成了对 inheritableThreadLocals 。

    get() 方法没有被重写,还是调用的ThreadLocal的get。在get()方法中:

ThreadLocalMap map = getMap(t);
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

    实际调用获取到的是,InheritableThreadLocal重写后的inheritableThreadLocals

    那到底是在何时何地传递过来的呢?

    InheritableThreadLocal的childValue方法注释中写道:Computes the child's initial value for this inheritable thread-local variable as a function of the parent's value at the time the child thread is created.  This method is called from within the parent thread before the child is started.

    大概意思是在子线程被创建的时候,做了从父线程传递值到子线程的操作。下面,看一下线程的创建过程:

    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
        init(g, target, name, stackSize, null, true);
    }
    private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        ......
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        ......
    }
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

    跟着进去几层后,发现了使用到inheritableThreadLocals的地方,继续看 ThreadLocal.createInheritedMap:

    static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
        return new ThreadLocalMap(parentMap);
    }
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

    真相就快浮出水面了,继续看 ThreadLocalMap 的构造方法:

        private ThreadLocalMap(ThreadLocalMap parentMap) {
            Entry[] parentTable = parentMap.table;
            int len = parentTable.length;
            setThreshold(len);
            table = new Entry[len];
            for (int j = 0; j < len; j++) {
                Entry e = parentTable[j];
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                    if (key != null) {
                        Object value = key.childValue(e.value);
                        Entry c = new Entry(key, value);
                        int h = key.threadLocalHashCode & (len - 1);
                        while (table[h] != null)
                            h = nextIndex(h, len);
                        table[h] = c;
                        size++;
                    }
                }
            }
        }
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

    可以看到,首先拿到父线程中的键值对表-table,然后提供for循环,把父线程中的这些值复制到我们新创建的线程的inheritableThreadLocals中。这种模式,有点类似于ClassLoader的 loadClass() 的机制

    总结:新创建的线程中 inheritableThreadLocals 中就已经有了值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值