上一篇文章中對ThreadLocal進行了詳盡的介紹,另外還有一個類:
InheritableThreadLocal
他是ThreadLocal的子類,那么這個類又有什么作用呢?
測試代碼
public class T25 { public static void main(String[] args) { //主線程中賦值 ThreadLocal<String> stringThreadLocal = new ThreadLocal<>(); InheritableThreadLocal<String> stringInheritableThreadLocal = new InheritableThreadLocal<>(); stringThreadLocal.set("ThreadLocal string"); stringInheritableThreadLocal.set("InheritableThreadLocal string"); //子線程中分別打印兩個變量的信息 new Thread(() -> { System.out.println( Thread.currentThread().getName() + " ThreadLocal value :" + stringThreadLocal.get()); System.out.println(Thread.currentThread().getName() + " InheritableThreadLocal value :" + stringInheritableThreadLocal.get()); }).start(); } }
在上面的測試代碼中,主線程中創建了兩個變量,類型分別為:ThreadLocal和InheritableThreadLocal
然后在主線程中創建了一個新的線程
在新的線程中,嘗試獲取他們的值
從打印信息可以看得出來
對於ThreadLocal獲取的值為null,而對於InheritableThreadLocal則能夠獲取到值
結論:
在子線程中,可以獲取到父線程的InheritableThreadLocal類型變量的值,而不能獲取到ThreadLocal類型變量的值
對於ThreadLocal我們已經有了詳盡的分析,在Thread中有一個map,以ThreadLocal類型的變量作為key
在子線程中,get方法自然是獲取子線程中的map,很顯然,子線程中的map並沒有設置任何值,所以初始值null被讀取出來
但是,InheritableThreadLocal為什么能夠讀取出來?
原理分析
在Thread類中,有一個ThreadLocal.ThreadLocalMap類型的變量:inheritableThreadLocals,他的類型同Thread內部的threadLocals變量
在Thread的init方法中,有一段初始化設置(應該還記得,這個init方法是所有的Thread對象創建的必經之路)
下面為部分代碼片段拼接
從上面的這個方法可以很清晰的看得到
如果parent的inheritableThreadLocals不是null,那么就會將當前線程的inheritableThreadLocals設置為parent的inheritableThreadLocals
parent是什么?之前也說過了,就是創建這個線程的線程,也就是平時說的父線程
所以說
借助於inheritableThreadLocals,可以實現,創建線程向被創建線程數據傳遞
看下下面的方法
邏輯很清晰,創建了一個ThreadLocalMap
inheritableThreadLocals就是ThreadLocalMap類型的
簡單理解:這個創建的ThreadLocalMap就是根據入參的ThreadLocalMap,拷貝創建一份
小結:
Thread對象,通過內部的
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
維護從父線程(創建該線程的線程)繼承而來的數據
原理就是在創建線程時,如果當前線程的inheritableThreadLocals不為null,那么將會復制一份保存在自己的ThreadLocal.ThreadLocalMap inheritableThreadLocals中
InheritableThreadLocal類解析
對比下 下面的兩幅圖片,上面為Thread中的相關方法
下圖為InheritableThreadLocal中的三個方法
很顯然,InheritableThreadLocal作為子類,重寫了這幾個方法
通過對getMap和createMap方法的重寫,可以看得出來,只是內部操作的變量發生了變化,從threadLocals轉換為inheritableThreadLocals
而對於childValue方法,還記得剛才的構造方法么(看注釋called only by createInheritedMap)
也就是說在父線程創建子線程,初始化InheritableThreadLocal時會用到
總結
InheritableThreadLocal的核心概念仍舊是ThreadLocal.ThreadLocalMap以及ThreadLocal
InheritableThreadLocal是 ThreadLocal的子類
在Thread內部通過維護 ThreadLocal.ThreadLocalMap inheritableThreadLocals 進行父子線程數據的傳遞
而這個數據則是通過在創建Thread對象的時候,借助於內部的init方法,調用createInheritedMap方法,從父線程(當前創建線程)中復制的一份
后續的數據讀取解析,則是通過inheritableThreadLocals變量,與內部的那個threadLocals沒有什么關系
換個思路理解,他就是另外一個ThreadLocal,假定Thread定義了兩個“ThreadLocal“,其中一個在創建線程的時候會從父線程復制一份
只不過從實現上、以及邏輯上,他繼承了ThreadLocal而已,然后覆蓋了幾個方法