Threadlocal的使用以及實現原理總結

NewHongjay發表於2018-09-12

Threadlocal總結

  • ThreadLocal 並不解決執行緒間共享資料的問題
  • ThreadLocal 通過隱式的在不同執行緒內建立獨立例項副本避免了例項執行緒安全的問題
  • 每個執行緒持有一個 Map(Map的key為ThreadLocal物件本身,值為ThreadLocal物件實際所包含的物件) 並維護了 ThreadLocal 物件與具體例項的對映,該 Map 由於只被持有它的執行緒訪問,故不存線上程安全以及鎖的問題
  • ThreadLocalMap 的 Entry 對 ThreadLocal 的引用為弱引用,避免了 ThreadLocal 物件無法被回收的問題
  • ThreadLocalMap 的 set 方法通過呼叫 replaceStaleEntry 方法回收鍵為 null 的 Entry 物件的值(即為具體例項)以及 Entry 物件本身從而防止記憶體洩漏
  • ThreadLocal 適用於變數線上程間隔離且在方法間共享的場景

Threadlocal 結構以及實現

  • 每個Thread物件有一個ThreadlocalMap屬性,ThreadlocalMap類始於Map的k-v結構。key是threadlocal物件,value就是threadlocal物件指向的實際物件。值得一提的是ThreadlocalMap對於hash衝突採用的是線性探測法來解決hash衝突的,不同於hashMap的拉鍊法。
  • threadlocal的set方法
    image.png
  • threadlocal的get方法
    image.png
  • 很明顯的看出每次執行threadlocal物件的get和set方法的時候就是先取出當前的執行緒t,然後再取出這個執行緒對應的ThreadlocalMap,再通過threadlocal物件作為key取出對應entry在取出entry的value。
  • 需要注意的是注意的是ThreadlocalMap是threadlocal的內部類,entry又是ThreadlocalMap的內部類
  • entry的key是弱引用從他的建構函式可以看出,為什麼是弱引用呢,因為當threadlocal物件不在使用的時候將其置位null,但是這個時候entry的key還是指向的threadlocal物件,如果這個時候是強引用就會導致threadlocal物件沒辦法回收會造成記憶體洩漏,所以改成弱引用的話當只有一個弱引用的entry的key指向threadlocal物件的時候Threadlocal物件在垃圾回收的時候就會被回收掉。
    image.png

關於ThreadLocal的記憶體洩露問題

  • 雖然Entry的Key對ThreadLocal物件是一個弱引用,保證了當除了Entry以外的引用指向ThreadLocal物件可以保證ThreadLocal物件被回收,但是對於Entry中的value的回收卻沒有像這樣解決

  • 對於Entry中的Value,因為是跟當前執行緒繫結,只要執行緒沒有被回收那麼這個Value是不會被回收的,特別是線上程池的情況下執行緒被複用導致Value一直不回被回收。如果執行緒執行完任務後馬上被回收就不會有這個問題

  • 關於這個value的記憶體洩露問題ThreadLocal也有自己的解決辦法,在ThreadLocalMap進行Set和get操作的時候,因為採用的是開放地址法解決hash衝突,有時候會因為在get和set的過程中會遍歷一部分ThreadLocalMap中的entry陣列,當發現key為null的entry的時候會主動清理掉這個無效的entry。

  • 還有就是當我們使用完一個ThreadLocal物件時,主動執行remove方法來清理記憶體。

  • 參考部落格:www.jasongj.com/java/thread…

相關文章