ThreadLocal原始碼探究 (JDK 1.8)
阿新 • • 發佈:2020-03-06
`ThreadLocal`類之前有了解過,看過一些文章,自以為對其理解得比較清楚了。偶然刷到了一道關於`ThreadLocal`記憶體洩漏的面試題,居然完全不知道是怎麼回事,痛定思痛,發現瞭解問題的本質還是需要從原始碼看起。
`ThreadLocal`可以儲存一些執行緒私有的資料,從而避免多執行緒環境下的資料共享問題。`ThreadLocal`儲存資料的功能是通過`ThreadLocalMap`實現的,這是`ThreadLocal`的一個靜態內部類。`ThreadLocal`原始碼加註釋總共`700`多行,`ThreadLocalMap`就佔據了接近`400`行,基本上理解了`ThreadLocalMap`也就理解了`ThreadLocal`。本文先簡介`ThreadLocalMap`,然後從`ThreadLocal`的核心方法開始講起,需要用到`ThreadLocalMap`的地方順帶一起介紹。
## 1.ThreadLocalMap簡介
`ThreadLocalMap`本質上仍然是一個`Map`,具有普通`Map`的特點,當遇到`hash`衝突的時候,採用線性探測的方式來解決衝突,底層使用陣列作為儲存結構,它的主要欄位如下:
- `INITIAL_CAPACITY`:初始容量,預設是`16`
- `Entry[] table`:儲存鍵值對的陣列,其大小是`2`的整數冪
- `size`:陣列記憶體儲的元素個數
- `threshold`:擴容閾值
`ThreadLocalMap`底層陣列儲存的是`Entry`型別鍵值對,`Entry`是`ThreadLocalMap`的一個內部類,它是用來儲存鍵值對的物件,值得關注的是`Entry`繼承了`WeakReference`這個弱引用類,這意味著`Entry的key`引用的物件,在沒有其他強引用的情況下,在下一次GC的時候就會被回收(注意:這裡忽略了軟引用,因為軟引用是在即將因為記憶體不足而丟擲異常的時候才會回收)。並且`Entry`的`key`是`ThreadLocal`物件,通過其祖父類`Reference`的建構函式可以看到,`key`實際上是被儲存在`referent`欄位中,`Entry`物件的`get`方法也是從`Reference`繼承過來的,直接返回該`referent`欄位。
```
static class Entry extends WeakR