开篇
数据在哪个线程存储,就要从哪个线程读取,子线程是读取不到的。那如果想要读取该怎么办呢?
示例
遇到开篇说的这种情况,可以使用InheritableThreadLocal
来帮助我们解决这类问题,InheritableThreadLocal
是 ThreadLocal
的子类,我们用 InheritableThreadLocal
和ThreadLocal
来演示下效果,便于更直观的理解。
@Test void contextLoads() throws InterruptedException { ThreadLocal threadLocal = new ThreadLocal(); threadLocal.set("蒋老湿"); System.out.println("threadLocal.get() = " + threadLocal.get()); // 子线程是读取不到的 new Thread(() -> { String name = Thread.currentThread().getName(); System.out.println(String.format("this is sub thread name:%s, threadLocal.get(): %s", name, threadLocal.get())); }).start(); Thread.sleep(1000); // ThreadLocal 修改为 InheritableThreadLocal ThreadLocal inheritableThreadLocal = new InheritableThreadLocal(); inheritableThreadLocal.set("蒋老湿inheritableThreadLocal"); System.out.println("inheritableThreadLocal.get() = " + inheritableThreadLocal.get()); // 在子线程中也能获取到父线程 ThreadLocal 中的数据。 new Thread(() -> { String name = Thread.currentThread().getName(); System.out.println(String.format("this is sub thread name:%s, inheritableThreadLocal.get(): %s", name, inheritableThreadLocal.get())); }).start(); } 复制代码
Tests passed:1of1test-1s 20 ms 1s 20ms threadLocal.get0)= 蒋老湿 15:20 ms 1s 20 ms this is sub thread name: Thread o. threadLocal. get O null inheritableThreadLocal.getO)=蒋老混inheritableThreadLocal this is sub thread name: Thread-1, inheritableThreadLocal.get () 蒋老混inheritableThreadLocal
InheritableThreadLocal解读
public class InheritableThreadLocal<T> extends ThreadLocal<T> { /** Creates an inheritable thread local variable.*/ public InheritableThreadLocal(){} /** Computes the child's initial value for this inheritable thread-local...*/ 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(firstKey: this,firstValue);
以上有三个方法,分别是:
- getMap():方法的返回值变成了 inheritableThreadLocals对象
- createMap(): 构建出 ThreadLocalMap 的对象复制给inheritableThreadLocals
- childValue(): 这个方法仅仅返回它的输入参数,并且应该被覆盖
和 ThreadLocal 相比,主要是保存数据的对象从 threadLocals属性 变为 inheritableThreadLocals属性。
set过程
ThreadLocalinheritableThreadLocal = newInheritableThreadLocal(); inheritableThreadLocal.set("蒋老湿inheritableThreadLocal");
set
方法会进入如下内容ThreadLocal#set(T value)
public void set(T value){ value:"蒋老湿inheritableThreadLocal" Thread t=Thread.currentThread(); t: "Thread[main,5,main]" ThreadLocalMap map = getMap(t); map: null if(map ≠null){ map.set(this, value); map:null} else { createMap(t,value); t:"Thread[main,5,main]”value:"蒋老湿inheritableT }
才是会调用java.lang.InheritableThreadLocal#createMap
,也就是给Thread
类的inheritableThreadLocals
变量赋值。
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( firstKey: this, firstValue);
什么时候调用createMap
在创建子线程的时候,通过红框部分可以了解到,如果父线程存在 inheritableThreadLocals
变量且不为null,就调用 ThreadLocal.createInheritedMap()
为该线程的 inheritableThreadLocals
变量赋值。
@ private Thread(ThreadGroup g, Runnable target, String name, long stacksize, AccessControlContext acc, boolean inheritThreadLocals){ if(name = null){..} this.name =name; Thread parent = currentThread(); SecurityManager security = System.getSecuritvManager(): if(g = null) {...} /* ... */ g.checkAccess(); /* ... */ if (security ≠ null) {...} g.addUnstarted(); this.group =g; this.daemon = parent.isDaemon(): this.priority = parent.getPriority(); if(security = null l1 isCcLOverridden(parent.getClass())) this.contextClassLoader = parent.getContextClassLoader(); else this.contextClassLoader = parent.contextClassLoader; this.inheritedAccessControlContext = acc ≠ null ? acc :AccessController.getContext(): this.target = target; setPriority(priority); if(inheritThreadLocals 8G parent.inheritableThreadLocals≠null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals): *Stash the specified stack size in case the vm cares * this.stacksize = stacksize;
ThreadLocal.createInheritedMap
方法所做的事情,其实就是将父线程的 inheritableThreadLocals
变量值赋值给子线程的 inheritableThreadLocals
变量。因此,在子线程中就可以访问到父线程 ThreadLocal
中的数据了。
这种复制不是实时同步,是在子线程创建的一瞬间才将父线程
inheritableThreadLocals
变量的值赋值给子线程,一旦子线程创建成功后,用户再次去修改了父线程inheritableThreadLocals
变量的值(即修改了父线程 ThreadLocal 中的数据),此时子线程是感知不到这个变化的。所以这里是值传递,不是引用传递。
好啦,经过上面的介绍大家应该搞清楚InheritableThreadLocal
是怎么一会事了吧