JDK源码:InheritableThreadLocal实现原理

一.ThreadLocal

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

ThreadLocal.ThreadLocalMap threadLocals = null;

    ThreadLocal的 set() 方法:拿到当前线程的 threadLocals,而后往其中塞值,key是ThreadLocal自己,value是塞入的值ide

取出Map的时候,若是为空,则初始化Map。this

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);
    }

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

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;
    }

 

二.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());
       }
}

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

Main Tread = 127
Son Thread = null

    使用 InheritableThreadLocal 以后的输出结果:继承

Main Tread = 127
Son Thread = 127

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

    看看 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);
    }
}

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

ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

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

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

ThreadLocalMap map = getMap(t);

    实际调用获取到的是,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);
        ......
    }

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

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

    真相就快浮出水面了,继续看 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++;
                    }
                }
            }
        }

    能够看到,首先拿到父线程中的键值对表-table,而后提供for循环,把父线程中的这些值复制到咱们新建立的线程的inheritableThreadLocals中。这种模式,有点相似于ClassLoader的 loadClass() 的机制

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

相关文章
相关标签/搜索