Java中的線程ThreadLocal詳細(xì)解析
一 Java中的引用關(guān)系
Java中的引用分為了強(qiáng)引用、弱引用、軟引用、虛引用
- 強(qiáng)引用: 垃圾回收的時候,如果內(nèi)存不足也不會進(jìn)行垃圾回收,會報out-of-memory異常
- 弱引用: 垃圾回收的時候,如果內(nèi)存不夠,則數(shù)據(jù)被回收.
- 軟引用: 垃圾回收的時候,軟引用會立刻進(jìn)行回收
- 虛引用: 垃圾回收的時候,軟引用會立刻進(jìn)行回收
二 ThreadLocal代碼實(shí)現(xiàn)
ThreadLocal是線程本地變量,存儲在ThreadLocal里面的數(shù)據(jù)都是 線程安全的.
一般ThreadLocal適用的場景多是各個線程間沒有變量共享需要的同步問題場景,比如一個簡單的SimpleDateFormat類,該類不是線程安全的,卻是有狀態(tài)的,如果將SimpleDateFormat設(shè)置為靜態(tài)的,所有線程共享,那么就會出現(xiàn)線程安全的問題,其中一個線程修改日期格式為“yyyyMMdd”,然后可能會影響到另外一個需要格式為“yyyy-MM-dd”的線程。但是如果在方法中每次用到的時候都new一個SimpleDateFormat類又太費(fèi)內(nèi)存(SimpleDateFormat這種簡單的類倒還好,若是一些比較占用資源的比如數(shù)據(jù)庫連接類等,就會讓加大整個數(shù)據(jù)庫的壓力),這時候采用ThreadLocal為每一個線程保存一份SimpleDateFormat副本,這樣既不會說每次調(diào)用方法都會生成一個對象,也不會在并發(fā)時產(chǎn)生線程同步問題。這就像是在共享一個靜態(tài)變量和每次使用都new一個對象兩者之間的一種折中處理方法。
自己實(shí)現(xiàn)的ThreadLocal
通過一個全局map, key是Thread對象,value是對應(yīng)存儲的數(shù)據(jù),這種情況下 如果map不銷毀,對應(yīng)的Thread線程就不發(fā)被回收,導(dǎo)致內(nèi)存泄露
JDK中使用的ThreadLocal
JDK8中在Thread對象中引用ThreadLocalMap,ThreadLocalMap的生命周期是Thread是同一個生命周期.
ThreadLocalMap的實(shí)現(xiàn)
(1) Entry數(shù)組實(shí)現(xiàn)
Entry數(shù)組是線程中實(shí)際存放數(shù)據(jù)的地方,key是ThreadLocal,是一個弱引用,value是對應(yīng)存儲的值.
為什么ThreadLocalMap#key是一個弱引用
如果外部不使用了ThreadLocal,則對應(yīng)的數(shù)據(jù)不應(yīng)該存儲在ThreadLocal中,應(yīng)該被刪除掉,防止內(nèi)存泄漏
ThreadLocalMap的屬性
private static final int INITIAL_CAPACITY = 16; //存儲數(shù)據(jù)的地方 private Entry[] table; // //數(shù)量 private int size = 0; private int threshold; // Default to 0
ThreadLocal的方法
ThreadLocal#set()方法
(1) 第一步 獲取到當(dāng)前線程的ThreadLocalMap
(2) 第二步 初始化ThreadLocalMap
(3) 第三步 將ThreadLocal作為key,value值作為值,設(shè)置到map中
ThreadLocal # get()方法
方法主要完成兩個功能: (1) 完成數(shù)據(jù)的讀取 (2) 將ThreadLocalMap中key為NULL的數(shù)據(jù)從ThreadLocalMap中刪除
ThreadLocalMap中的entry其實(shí)是繼承的弱引用,如果該弱引用指向的ThreadLocal沒有在外部被強(qiáng)引用指向的話,在下次gc的時候就會被回收,那這樣的話就會出現(xiàn)ThreadLocalMap中存在key為null的情況,這樣的數(shù)據(jù)對于map來講是臟數(shù)據(jù),這樣的臟數(shù)據(jù)沒有用,卻一直占用著map的存儲空間,這其實(shí)就是一種內(nèi)存泄漏,所以需要來釋放掉這些空間
三 ThreadLocalMap的內(nèi)存泄漏問題
如果ThreadLocal無強(qiáng)引用進(jìn)行應(yīng)用,則在垃圾回收的時候會把這個key進(jìn)行回收.
這個時候,因?yàn)榫€程還存活,所以ThreadLocalMap依舊存在,但是key為null,這個 key對應(yīng)的value就無法被訪問到了,造成內(nèi)存泄漏.
JDK團(tuán)隊(duì)自己的解決辦法
調(diào)用get()、set()方法的時候,自動清理掉ThreadLocalMap中key為null的數(shù)據(jù)
開發(fā)者的解決辦法 使用ThreadLocal后,調(diào)用ThreadLocal
到此這篇關(guān)于Java中的線程ThreadLocal詳細(xì)解析的文章就介紹到這了,更多相關(guān)Java的ThreadLocal內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot+thymeleaf+Echarts+Mysql 實(shí)現(xiàn)數(shù)據(jù)可視化讀取的示例
本文主要介紹了SpringBoot+thymeleaf+Echarts+Mysql 實(shí)現(xiàn)數(shù)據(jù)可視化讀取的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04JAVA 截取字符串的三種方法 subString,StringUtils,split實(shí)例詳解
這篇文章給大家介紹JAVA 截取字符串的三種方法 subString,StringUtils,split,每種方法結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-12-12完美解決springboot中使用mybatis字段不能進(jìn)行自動映射的問題
今天在springboot中使用mybatis的時候不能字段不能夠進(jìn)行自動映射,接下來給大家給帶來了完美解決springboot中使用mybatis字段不能進(jìn)行自動映射的問題,需要的朋友可以參考下2023-05-05SpringBoot中注解@ConfigurationProperties與@Value的區(qū)別與使用詳解
本文主要介紹了SpringBoot中注解@ConfigurationProperties與@Value的區(qū)別與使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09SpringBoot實(shí)現(xiàn)IP地址解析的示例代碼
本篇帶大家實(shí)踐在springboot項(xiàng)目中獲取請求的ip與詳細(xì)地址,我們的很多網(wǎng)站app中都已經(jīng)新增了ip地址顯示,具有一定的參考價值,感興趣的可以了解一下2024-01-01java如何不通過構(gòu)造函數(shù)創(chuàng)建對象(Unsafe)
這篇文章主要介紹了java如何不通過構(gòu)造函數(shù)創(chuàng)建對象(Unsafe)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03