InheritableThreadLocal实现原理java
ThreadLocal 实现原理 : https://my.oschina.net/xinxingegeya/blog/297192ide
来回顾一下 ThreadLocal 实现原理:this
从上面的介绍咱们能够知道,咱们实际上是根据 Thread.currentThread(),拿到该线程的 threadlocals,从而进一步获得咱们以前预先 set 好的值。那么若是咱们新开一个线程,这个时候,因为 Thread.currentThread() 已经变了,从而致使得到的 threadlocals 不同,咱们以前并无在这个新的线程的 threadlocals 中放入值,那么我就再经过 threadlocal.get()方法 是不可能拿到值的。例如以下代码:spa
public class Test { public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(); public static void main(String args[]){ threadLocal.set(new Integer(123)); Thread thread = new MyThread(); thread.start(); System.out.println("main = " + threadLocal.get()); } static class MyThread extends Thread{ @Override public void run(){ System.out.println("MyThread = " + threadLocal.get()); } } }
输出是:.net
main = 123线程
MyThread = nullcode
那么这个时候怎么解决? InheritableThreadLocal 就能够解决这个问题。先看一个官方对它的介绍:orm
* This class extends <tt>ThreadLocal</tt> to provide inheritance of valuesblog
* from parent thread to child thread: when a child thread is created, theci
* child receives initial values for all inheritable thread-local variables
* for which the parent has values. Normally the child's values will be
* identical to the parent's; however, the child's value can be made an
* arbitrary function of the parent's by overriding the <tt>childValue</tt>
* method in this class.
也就是说,咱们把上面的
public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
改为
public static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<Integer>();
再运行,就会有结果:
main = 123
MyThread = 123
也就是子线程或者说新开的线程拿到了该值。 那么,这个到底是怎么实现的呢,key 都变了,为何还能够拿到呢?
InheritableThreadLocal 的代码很简单 以下所示,
public class InheritableThreadLocal<T> extends ThreadLocal<T> { /** * 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. * <p> * This method merely returns its input argument, and should be overridden * if a different behavior is desired. * * @param parentValue the parent thread's value * @return the child thread's initial value */ protected T childValue(T parentValue) { return parentValue; } /** * Get the map associated with a ThreadLocal. */ ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; } /** * Create the map associated with a ThreadLocal. */ void createMap(Thread t, T firstValue) { t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue); } }
其实就是重写了3个方法。
首先,当咱们调用 get 方法的时候,因为子类没有重写,因此咱们调用了父类的 get 方法:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
这里会有一个Thread.currentThread() , getMap(t) 方法,因此就会获得这个线程 threadlocals。 可是,因为子类 InheritableThreadLocal 重写了 getMap()方法,再看上述代码,咱们能够看到:
其实不是获得 threadlocals,而是获得 inheritableThreadLocals。 inheritableThreadLocals 以前一直没说起过,其实它也是 Thread 类的一个 ThreadLocalMap 类型的 属性,以下 Thread 类的部分代码:
ThreadLocal.ThreadLocalMap threadLocals = null; ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
那么,这里看 InheritableThreadLocal 重写的方法,感受 inheritableThreadLocals 和 threadLocals 几乎是如出一辙的做用,只是换了个名字并且,那么究竟 为何在新的线程中经过 threadlocal.get() 方法还能获得值呢?
这时候要注意 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.
这个时候,你明白了,是否是在 建立线程的时候作了手脚,作了一些值的传递,或者这里利用上了 inheritableThreadLocals 之类的。
其实,是的:关键在于 Thread thread = new MyThread();
这不是一个简简单单的 new 操做。当咱们 new 一个 线程的时候:
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); }
而后:
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) { ...... if (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); ...... }
这时候有一句 'ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);' ,而后
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) { return new ThreadLocalMap(parentMap); }
继续跟踪:
/** * Construct a new map including all Inheritable ThreadLocals * from given parent map. Called only by createInheritedMap. * * @param parentMap the map associated with parent thread. */ 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) { ThreadLocal key = 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++; } } } }
当咱们建立一个新的线程的时候X,X线程就会有 ThreadLocalMap 类型的 inheritableThreadLocals ,由于它是 Thread 类的一个属性。
先获得当前线程存储的这些值,例如 Entry[] parentTable = parentMap.table; 。再经过一个 for 循环,不断的把当前线程的这些值复制到咱们新建立的线程X 的inheritableThreadLocals 中。就这样,就ok了。
那么这样会有一个什么结果呢?
结果就是咱们建立的新线程X 的inheritableThreadLocals 变量中已经有了值了。那么我在新的线程X中调用 threadlocal.get() 方法,首先会获得新线程X 的 inheritableThreadLocals,而后,再根据threadlocal.get()中的 threadlocal,就可以获得这个值。
这样就避免了 新线程中获得的 threadlocals 没有东西。以前就是由于没有东西,因此才拿不到值。
因此说 整个 InheritableThreadLocal 的实现原理就是这样的。
===============END===============