一、前言

多个线程应用共享变量时,如果要保障线程平安,通常会加锁,synchronized或者Lock。但这两种锁都是重量级的,如果多个线程都心愿操作各自的变量,彼此间互不影响,那么ThreadLocal就派上用场了,InheritableThreadLocal则是它的性能扩大,前面会剖析它的应用场景。

二、ThreadLocal实现原理

先来看下它的类构造:

红色框中的是咱们罕用的办法,它外部是用ThreadLocalMap实现的,尽管命名有Map后缀,但并没有实现Map接口,来看下它的构造:

static class ThreadLocalMap {   static class Entry extends WeakReference<ThreadLocal<?>> {        /** The value associated with this ThreadLocal. */        Object value;        Entry(ThreadLocal<?> k, Object v) {            super(k);            value = v;        }    }    private Entry[] table;}

能够看到,ThreadLocalMap外部是用Entry[]来保留线程变量的,key是ThreadLocal实例自身,并不是以后线程Thread哦,value就是要用的变量。
先来看set()办法:

public void set(T value) {    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    if (map != null)        map.set(this, value);    else createMap(t, value);}

①先获取以后线程t对应的ThreadLocalMap实例,getMap代码如下:

ThreadLocalMap getMap(Thread t) {    return t.threadLocals;}

能够看到,Thread外部有个ThreadLocalMap类型的援用
Thread.java

ThreadLocal.ThreadLocalMap threadLocals = null;

②如果map不为空,保留值,this即为以后ThreadLocal实例,value为咱们要用的变量
③如果map为空,则createMap,代码如下:

void createMap(Thread t, T firstValue) {    t.threadLocals = new ThreadLocalMap(this, firstValue);}

来看看ThreadLocalMap的构造函数做了哪些事件:

ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {    // 初始化Entry[]    table = new Entry[INITIAL_CAPACITY];    // 计算firstValue放在该数组的地位i    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);    // 赋值    table[i] = new Entry(firstKey, firstValue);    size = 1;    // 设置阈值,扩容会用到    setThreshold(INITIAL_CAPACITY);}

setThreshold办法如下:

/** * Set the resize threshold to maintain at worst a 2/3 load factor. */private void setThreshold(int len) {    threshold = len * 2 / 3;}

代码也很简略,看正文就能明确,这里的实现思路和HashMap差不多。
再来看get()办法:

public T get() {    // 获取以后线程t    Thread t = Thread.currentThread();    // 获取以后线程t对应的ThreadLocalMap    ThreadLocalMap map = getMap(t);    if (map != null) {        // 获取以后ThreadLocal实例对应的线程变量        ThreadLocalMap.Entry e = map.getEntry(this);        if (e != null) {            @SuppressWarnings("unchecked")            T result = (T)e.value;            return result;        }    }    // map为空则初始化    return setInitialValue();}

setInitialValue()代码如下:

private T setInitialValue() {    // 获取设定的初始化值,默认为null,用户能够调用它来设置初始值    T value = initialValue();    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    // map不为空则设置初始化值,否则创立map    if (map != null)        map.set(this, value);    else createMap(t, value);    return value;}

最初看下remove()办法:

public void remove() {    ThreadLocalMap m = getMap(Thread.currentThread());    // 删除以后ThreadLocal实例对应的变量    if (m != null)        m.remove(this);}

罕用的set(),get(),remove()办法逻辑都很清晰明了,就不做赘述了

三、InheritableThreadLocal的作用

咱们晓得,ThreadLocal在应用过程中,各个线程之间的变量是互不影响的,子线程没法拿到父线程的本地变量,这也是失常的。但有时候也有这样的需要场景,子线程须要拿到父线程的变量,比方子线程须要应用寄存在ThreadLocal变量中的用户登录信息,再比方一些中间件须要把对立的id追踪的整个调用链路记录下来。那么InheritableThreadLocal就能够做这个事件。上面来看看它是怎么实现的吧。

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

能够看到,InheritableThreadLocal类继承了ThreadLocal,并重写了getMap()和createMap(),外面呈现了个t.inheritableThreadLocals,它就是实现共享变量的要害,它替换了t.threadLocals,所有原先对t.threadLocals的操作都改成了t.inheritableThreadLocals。它和t.threadLocals类型一样,也是Thread的一个属性。

ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

但目前如同还是看不出来起共享成果的是哪段代码?它暗藏的很深,在Thread的构造函数里,来看看吧:

public Thread(Runnable target) {    init(null, target, "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) { ... // parent指的是调用new Thread()的线程,即main线程 Thread parent = currentThread(); ... if (inheritThreadLocals && parent.inheritableThreadLocals != null)        this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); ...}

为了不便解说,省略了些代码,只看对inheritableThreadLocals起作用的。
来看看ThreadLocal.createInheritedMap()代码:

static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {    return new ThreadLocalMap(parentMap);}
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) {                // childValue()就是父线程的e.value                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++;            }         }     }}

能够看到,构造函数就是把父线程的ThreadLocalMap里的Entry[]拷贝到子线程中,实现变量的共享。
到这里本文就完结了,谢谢观看。