InheritableThreadLocal類原理簡介使用 父子線程傳遞數據詳解 多線程中篇(十八)


 
上一篇文章中對ThreadLocal進行了詳盡的介紹,另外還有一個類:
InheritableThreadLocal
他是ThreadLocal的子類,那么這個類又有什么作用呢?
image_5c77364a_33e3
 

測試代碼

 

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則能夠獲取到值
image_5c77364a_7c3
結論:
在子線程中,可以獲取到父線程的InheritableThreadLocal類型變量的值,而不能獲取到ThreadLocal類型變量的值
對於ThreadLocal我們已經有了詳盡的分析,在Thread中有一個map,以ThreadLocal類型的變量作為key
在子線程中,get方法自然是獲取子線程中的map,很顯然,子線程中的map並沒有設置任何值,所以初始值null被讀取出來
但是,InheritableThreadLocal為什么能夠讀取出來?

原理分析

在Thread類中,有一個ThreadLocal.ThreadLocalMap類型的變量:inheritableThreadLocals,他的類型同Thread內部的threadLocals變量
image_5c77364a_13aa
在Thread的init方法中,有一段初始化設置(應該還記得,這個init方法是所有的Thread對象創建的必經之路)
下面為部分代碼片段拼接
image_5c77364a_2ad4
從上面的這個方法可以很清晰的看得到
如果parent的inheritableThreadLocals不是null,那么就會將當前線程的inheritableThreadLocals設置為parent的inheritableThreadLocals
parent是什么?之前也說過了,就是創建這個線程的線程,也就是平時說的父線程
所以說
借助於inheritableThreadLocals,可以實現,創建線程向被創建線程數據傳遞
看下下面的方法
邏輯很清晰,創建了一個ThreadLocalMap
inheritableThreadLocals就是ThreadLocalMap類型的
簡單理解:這個創建的ThreadLocalMap就是根據入參的ThreadLocalMap,拷貝創建一份
image_5c77364a_68
小結:
Thread對象,通過內部的
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
維護從父線程(創建該線程的線程)繼承而來的數據
原理就是在創建線程時,如果當前線程的inheritableThreadLocals不為null,那么將會復制一份保存在自己的ThreadLocal.ThreadLocalMap inheritableThreadLocals中

InheritableThreadLocal類解析

對比下 下面的兩幅圖片,上面為Thread中的相關方法
下圖為InheritableThreadLocal中的三個方法
很顯然,InheritableThreadLocal作為子類,重寫了這幾個方法
image_5c77364a_7073
 
image_5c77364b_73a8
通過對getMap和createMap方法的重寫,可以看得出來,只是內部操作的變量發生了變化,從threadLocals轉換為inheritableThreadLocals
而對於childValue方法,還記得剛才的構造方法么(看注釋called only by createInheritedMap)
也就是說在父線程創建子線程,初始化InheritableThreadLocal時會用到
image_5c77364b_45a1

總結

InheritableThreadLocal的核心概念仍舊是ThreadLocal.ThreadLocalMap以及ThreadLocal
InheritableThreadLocal是 ThreadLocal的子類
在Thread內部通過維護    ThreadLocal.ThreadLocalMap inheritableThreadLocals 進行父子線程數據的傳遞
而這個數據則是通過在創建Thread對象的時候,借助於內部的init方法,調用createInheritedMap方法,從父線程(當前創建線程)中復制的一份
后續的數據讀取解析,則是通過inheritableThreadLocals變量,與內部的那個threadLocals沒有什么關系
換個思路理解,他就是另外一個ThreadLocal,假定Thread定義了兩個“ThreadLocal“,其中一個在創建線程的時候會從父線程復制一份
只不過從實現上、以及邏輯上,他繼承了ThreadLocal而已,然后覆蓋了幾個方法
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM