ThreadLocal源碼分析、使用場景、內存泄漏(一)

? ? 1、ThreadLocal線程的局部變量。既然是線程局部變量,那么理所當然就應該存儲在自己的線程對象中,我們可以從 Thread 的源碼中找到線程局部變量存儲的地方:

我們可以看到線程局部變量是存儲在Thread對象的 threadLocals 屬性中,而 threadLocals 屬性是一個 ThreadLocal.ThreadLocalMap 對象。

2、ThreadLocalMap是什么呢?

可以看到他是ThreadLocal的一個靜態(tài)內部類,內部是一個自己實現(xiàn)的以ThreadLocal為key值的map,使用了弱引用的方式。方便內存的回收。

從構造函數(shù)中可以看出,他是一個 private Entry[] table數(shù)組,通過firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1)實現(xiàn)key到value的映射,初始化大小為16。

threadLocalHashCode 是一個原子變量每次增加0x61c88647實現(xiàn),然后?& (INITIAL_CAPACITY - 1)?取得在數(shù)組?private?Entry[] table?中的索引。

3、ThreadLocal初始化

首先在當前線程中獲取threadLoals,如果為null,則進行初始化工作。

4、內存的回收

ThreadLocal 涉及到的兩個層面的內存自動回收

????當線程死亡時,那么所有的保存在的線程局部變量就會被回收,其實這里是指線程Thread對象中的 ThreadLocal.ThreadLocalMap threadLocals 會被回收,這是顯然的。

如果線程可以活很長的時間,并且該線程保存的線程局部變量有很多(也就是 Entry 對象很多),那么就涉及到在線程的生命期內如何回收?ThreadLocalMap?的內存了,不然的話,Entry對象越多,那么ThreadLocalMap?就會越來越大,占用的內存就會越來越多,所以對于已經不需要了的線程局部變量,就應該清理掉其對應的Entry對象。使用的方式是,Entry對象的key是WeakReference 的包裝,當ThreadLocalMap?的?private Entry[] table,已經被占用達到了三分之二時 threshold = 2/3(也就是線程擁有的局部變量超過了10個) ,就會嘗試回收 Entry 對象,我們可以看到?ThreadLocalMap.set方法中有下面的代碼:

if?(!cleanSomeSlots(i, sz) && sz >= threshold)

????rehash();

5、 ThreadLocal常用的接口:

1)需要制定初始值時,可以覆蓋protected T initialValue()方法;

2)public T get();

3)public void set(T value);

4)public void remove();

6、總結

1)一個線程中的所有的局部變量其實存儲在該線程自己的同一個map屬性中;

2)線程死亡時,線程局部變量會自動回收內存;

3)線程局部變量時通過一個 Entry 保存在map中,該Entry 的key是一個 WeakReference包裝的ThreadLocal, value為線程局部變量;?

???? key 到 value 的映射是通過:ThreadLocal.threadLocalHashCode & (INITIAL_CAPACITY - 1) 來完成的;

4)當線程擁有的局部變量超過了容量的2/3(沒有擴大容量時是10個),會涉及到ThreadLocalMap中Entry的回收;

參考文章:https://www.cnblogs.com/digdeep/p/4510875.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容