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 中就已經有了值

相關文章
相關標籤/搜索