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; }
首先看一個例子:線程
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 中就已經有了值。