ThreadLocal實現原理詳解
簡書 滌生。
轉載請注明原創(chuàng)出處,謝謝!
如果讀完覺得有收獲的話,歡迎點贊加關注。
介紹
?ThreadLocal大家應該不陌生,經常在一些同步優(yōu)化中會使用到它。很多地方叫線程本地變量,ThreadLocal為變量在每個線程中都創(chuàng)建了一個副本,那么每個線程可以訪問自己內部的副本變量。也就是對于同一個ThreadLocal,每個線程通過get、set、remove接口操作只會影響自身線程的數據,不會干擾其他線程中的數據。
ThreadLocal是怎么實現的呢?
ThreadLocal又有哪些誤區(qū)呢?
源碼分析
從ThreadLocal的set方法說起,set是用來設置想要在線程本地的數據,可以看到先拿到當前線程,然后獲取當前線程的ThreadLocalMap,如果map不存在先創(chuàng)建map,然后設置本地變量值。

那ThreadLocalMap又是什么?跟線程有什么關系?可以看到ThreadLocalMap其實是線程自身的一個成員屬性threadLocals的類型。也就是線程本地數據都存在這個threadLocals應用的ThreadLocalMap中。

我們再接著看看ThreadLocalMap,跟想象中的Map有點不一樣,它其實內部是有個Entry數組,將數據包裝成靜態(tài)內部類Entry對象,存儲在這個table數組中,數組的下標是threadLocal的threadLocalHashCode&(INITIAL_CAPACITY-1),因為數組的大小是2的n次方,那其實這個值就是threadLocalHashCode%table.length,用&而不用%,其實是提升效率。只要數組的大小不變,這個索引下標是不變的,這也方便去set和get數據。

我們再看看Entry的定義,Entry繼承自WeakReference(這么做目的是什么,后面會講到),構造方法有兩個參數一個是threadLocal對象,一個是線程本地的變量。

看到這里大家應該就明白了,每個線程自身都維護著一個ThreadLocalMap,用來存儲線程本地的數據,可以簡單理解成ThreadLocalMap的key是ThreadLocal變量,value是線程本地的數據。就這樣很簡單的實現了線程本地數據存儲和交互訪問。
誤區(qū)
上文也提到了,Entry繼承自WeakReference,大家都知道WeakReference(弱引用)的特性,只要從根集出發(fā)的引用中沒有有效引用指向該對象,則該對象就可以被回收,這里的有效引用并不包含WeakReference,所以弱引用不影響對象被GC。
這里被WeakReference引用的對象是哪個呢?可以看Entry的構造方法,很容易看出指的是ThreadLocal自身,也就是說ThreadLocal自身的回收不受ThreadLocalMap的這個弱引用的影響,讓用戶減輕GC的煩惱。
但是不用做些什么嗎?這么簡單?
其實不然,ThreadLocalMap還做了其他的工作,試想一下,ThreadLocal對象如果外界沒有有效引用,是能夠被GC,但是Entry呢?Entry也能自動被GC嗎,當然不行,Entry還被ThreadLocalMap的table數組強引用著呢。
所以ThreadLocalMap該做點什么?
我看看ThreadLocalMap的expungeStaleEntry這個方法,這個方法在ThreadLocalMap get、set、remove、rehash等方法都會調用到,看下面標紅的兩處代碼,第一處是將remove的entry賦空,第二次處是找到已經被GC的ThreadLocal,然后會清理掉table數組對entry的引用。這樣entry在后續(xù)的GC中就會被回收。

是不是這樣就萬事大吉了呢,不用擔心GC問題了呢?
沒那么簡單,還是有點坑:
這里的坑與WeakHashMap垃圾回收原理中所說的類似,如果數據初始化好之后,一直不調用get、set等方法,這樣Entry就一直不能回收,導致內存泄漏。所以一旦數據不使用最好主動remove。
有些同學問,如果線程資源回收了,還會泄漏嗎?
當然不會,線程回收后,存在線程相關的ThreadLocalMap也會被回收,線程相關的本地數據自然也會回收。但是不要忘記ThreadLocal的使用場景,就是用來存儲線程本地變量,大部分場景中,線程都是一直存活或者長時間存活。
場景
一般在連接池優(yōu)化上會使用到ThreadLocal,在多線程獲取連接池時,會有同步操作,影響性能。如果使用ThreadLocal,每個線程使用自己的獨立連接,性能會有一定的提升。
總結
希望這遍文章能夠提升大家對ThreadLocal的理解,避免踩坑,使用起來也更加了然于胸。