我們都知道線程本地變量表也就是ThreadLocal在我們做線程級的數據隔離時非常好用,但是有時候我們會想如何讓子線程獲取到父線程的ThreadLocal,其實在線程中除了ThreadLocal外還有InheritableThreadLocal,顧名思義,可繼承的線程變量表,可以讓子線程獲取到父線程中ThreadLocal的值。
public class BaseTest { public static final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>(); public static final ThreadLocal<String> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { inheritableThreadLocal.set("Inheritable hello"); threadLocal.set("hello"); new Thread(()->{ System.out.println(String.format("子線程可繼承值:%s",inheritableThreadLocal.get())); System.out.println(String.format("子線程值:%s",threadLocal.get())); new Thread(()->{ System.out.println(String.format("孫子線程可繼承值:%s",inheritableThreadLocal.get())); System.out.println(String.format("孫子線程值:%s",threadLocal.get())); }).start(); }).start(); }
執行后獲取返回值。
可以看到不可繼承的ThreadLocal子線程是不能共享父線程的。可繼承的ThreadLocal如何實現呢?
其原理和ThreadLocal基本上一致,都是線程中存有ThreadLocalMap
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null; /* * InheritableThreadLocal values pertaining to this thread. This map is * maintained by the InheritableThreadLocal class. */ ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
我們在new線程時init方法會有如下操作。
Thread parent = currentThread();
../省略代碼 if (inheritThreadLocals && parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
如果允許new的線程繼承當前線程的threadlocalMap,那么new的線程會copy一份當前線程也就是父線程的inheritableThreadLocals 。這兒也可以說明繼承有兩條件,new的線程允許繼承(默認允許),父線程的inheritableThreadLocals 不為null。
**這兒要注意不管是創建ThreadLocal還是inheritableThreadLocals(如果父線程沒有) 的ThreadLocalMap都是在Threadlocal.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); }