ThreadLocal是什么
ThreadLocal是一個本地線程副本變量工具類。主要用于將私有線程和該線程存放的副本對象做一個映射,各個線程之間的變量互不干擾,在高并發(fā)場景下,可以實現(xiàn)無狀態(tài)的調(diào)用,特別適用于各個線程依賴不通的變量值完成操作的場景。
下圖為ThreadLocal的內(nèi)部結(jié)構(gòu)圖

從上面的結(jié)構(gòu)圖,我們已經(jīng)窺見ThreadLocal的核心機(jī)制:
- 每個Thread線程內(nèi)部都有一個Map。
- Map里面存儲線程本地對象(key)和線程的變量副本(value)
- 但是,Thread內(nèi)部的Map是由ThreadLocal維護(hù)的,由ThreadLocal負(fù)責(zé)向map獲取和設(shè)置線程的變量值。
所以對于不同的線程,每次獲取副本值時,別的線程并不能獲取到當(dāng)前線程的副本值,形成了副本的隔離,互不干擾。
基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
- 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
- 視頻教程:https://doc.iocoder.cn/video/
ThreadLocalMap

ThreadLocalMap是ThreadLocal的內(nèi)部類,沒有實現(xiàn)Map接口,用獨立的方式實現(xiàn)了Map的功能,其內(nèi)部的Entry也獨立實現(xiàn)。
和HashMap的最大的不同在于,ThreadLocalMap結(jié)構(gòu)非常簡單,沒有next引用,也就是說ThreadLocalMap中解決Hash沖突的方式并非鏈表的方式,而是采用線性探測的方式。(ThreadLocalMap如何解決沖突? )
在ThreadLocalMap中,也是用Entry來保存K-V結(jié)構(gòu)數(shù)據(jù)的。但是Entry中key只能是ThreadLocal對象,這點被Entry的構(gòu)造方法已經(jīng)限定死了。
staticclassEntryextendsWeakReference<ThreadLocal>{
/**ThevalueassociatedwiththisThreadLocal.*/
Objectvalue;
Entry(ThreadLocalk,Objectv){
super(k);
value=v;
}
}
注意了!!
Entry繼承自WeakReference(弱引用,生命周期只能存活到下次GC前),但只有Key是弱引用類型的,Value并非弱引用。(問題馬上就來了)
由于ThreadLocalMap的key是弱引用,而Value是強(qiáng)引用。這就導(dǎo)致了一個問題,ThreadLocal在沒有外部對象強(qiáng)引用時,發(fā)生GC時弱引用Key會被回收,而Value不會回收。
當(dāng)線程沒有結(jié)束,但是ThreadLocal已經(jīng)被回收,則可能導(dǎo)致線程中存在ThreadLocalMap的鍵值對,造成內(nèi)存泄露。(ThreadLocal被回收,ThreadLocal關(guān)聯(lián)的線程共享變量還存在)。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
- 項目地址:https://github.com/YunaiV/yudao-cloud
- 視頻教程:https://doc.iocoder.cn/video/
如何避免泄漏
為了防止此類情況的出現(xiàn),我們有兩種手段。
1、使用完線程共享變量后,顯示調(diào)用ThreadLocalMap.remove方法清除線程共享變量;
既然Key是弱引用,那么我們要做的事,就是在調(diào)用ThreadLocal的get()、set()方法時完成后再調(diào)用remove方法,將Entry節(jié)點和Map的引用關(guān)系移除,這樣整個Entry對象在GC Roots分析后就變成不可達(dá)了,下次GC的時候就可以被回收。
2、JDK建議ThreadLocal定義為private static,這樣ThreadLocal的弱引用問題則不存在了。
審核編輯 :李倩
-
變量
+關(guān)注
關(guān)注
0文章
615瀏覽量
29396 -
線程
+關(guān)注
關(guān)注
0文章
508瀏覽量
20772 -
Thread
+關(guān)注
關(guān)注
2文章
91瀏覽量
27280
原文標(biāo)題:ThreadLocal 搭配線程池使用造成內(nèi)存泄漏的原因和解決方案
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
AURIX? Audio Application Kit for AURIX? lite Kit V2 深度解析
EiceDRIVER? 2EDR8259H等雙通道隔離柵極驅(qū)動器IC:設(shè)計與應(yīng)用詳解
雙向保護(hù)開關(guān)評估套件使用指南
雙向保護(hù)開關(guān)評估套件使用指南:從原理到實戰(zhàn)
EVAL_6EDL7141_FOC_3SH 1 kW評估板:助力三相無刷直流電機(jī)驅(qū)動設(shè)計
探索CY4535 EZ - PD? BCR - LITE評估套件:開啟USB Type - C電源適配新旅程
冬季電瓶修復(fù)該加些什么?
兩節(jié)串聯(lián)鋰電池充電管理芯片,普通,高壓,快充輸入選型介紹

ThreadLocal是什么
評論