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