ThreadLocal的使用和實現原理

ThreadLocal的使用和實現原理

ThreadLocal的使用和實現原理

ThreadLocal是什麼?

ThreadLocal提供線程本地變量,每個線程擁有本地變量的副本,各個線程之間的變量互不干擾。ThreadLocal實現在多線程環境下去保證變量的安全。以下來源於ThreadLocal類的註釋。

This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable.

ThreadLocal的使用

JDK中的例子,定一個一個私有的,靜態的ThreadLocal變量,並且重寫了initialValue方法,每個線程都會調用這個方法,獲得初始化值。

ThreadLocal的使用和實現原理

JDK中的例子


如果需要我們可以重寫initialValue方法,實現自己的業務邏輯。

使用其實很簡單,保存值就調用set方法,獲得值調用get方法,最後調用remove方法刪除數據,防止內存洩漏和數據混亂。

ThreadLocal的數據結構

Thread類中有個變量threadLocals,這個類型為ThreadLocal中的一個內部類ThreadLocalMap,這個類沒有實現map接口,就是一個普通的Java類,但是實現的類似map的功能。

ThreadLocal的使用和實現原理

ThreadLocal數據結構

每個線程都要自己的一個map,map是一個數組的數據結構存儲數據,每個元素是一個Entry,entry的key是threadlocal的引用,也就是當前變量的副本,value就是set的值。

ThreadLocal的源碼分析

1、Thread類中有個變量threadLocals,類型為
ThreadLocal.ThreadLocalMap,這個就是保存每個線程的私有數據。

ThreadLocal的使用和實現原理

threadLocals

2、ThreadLocalMap是ThreadLocal的內部類,每個數據用Entry保存,其中的Entry繼承與WeakReference,用一個鍵值對存儲,鍵為ThreadLocal的引用。

為什麼是WeakReference呢?如果是強引用,即使把ThreadLocal設置為null,GC也不會回收,因為ThreadLocalMap對它有強引用。

ThreadLocal的使用和實現原理

Entry的定義

3、ThreadLocal中的set方法的實現邏輯,先獲取當前線程,取出當前線程的ThreadLocalMap,如果不存在就會創建一個ThreadLocalMap,如果存在就會把當前的threadlocal的引用作為鍵,傳入的參數作為值存入map中。

ThreadLocal的使用和實現原理

set方法

4、ThreadLocal中get方法的實現邏輯,獲取當前線程,取出當前線程的ThreadLocalMap,用當前的threadlocak作為key在ThreadLocalMap查找,如果存在不為空的Entry,就返回Entry中的value,否則就會執行初始化並返回默認的值。

ThreadLocal的使用和實現原理

get方法

5、ThreadLocal中remove方法的實現邏輯,還是先獲取當前線程的ThreadLocalMap變量,如果存在就調用ThreadLocalMap的remove方法。ThreadLocalMap的存儲就是數組的實行,因此需要確定元素的位置,找到Entry,把entry的鍵值對都設為null,最後也Entry也設置為null。其實這其中會有哈希衝突,具體見下文。

ThreadLocal的使用和實現原理

remove方法

解決哈希衝突

ThreadLocal中的hash code非常簡單,就是調用AtomicInteger的getAndAdd方法,參數是個固定值0x61c88647。

上面說過ThreadLocalMap的結構非常簡單隻用一個數組存儲,並沒有鏈表結構,當出現Hash衝突時採用線性查找的方式,所謂線性查找,就是根據初始key的hashcode值確定元素在table數組中的位置,如果發現這個位置上已經有其他key值的元素被佔用,則利用固定的算法尋找一定步長的下個位置,依次判斷,直至找到能夠存放的位置。如果產生多次hash衝突,處理起來就沒有HashMap的效率高,為了避免哈希衝突,使用盡量少的threadlocal變量

最後

使用場景:一些ORM框架的Session管理,web系統的會話管理等

簡單總結:一個ThreadLocal只能保存一個變量的副本,如果需要多個,就得創建多個變量;我們確定使用完需要執行remove避免內存洩漏。


分享到:


相關文章: