日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

有沒有并發(fā)編程經(jīng)驗,一問這個類便知!

來源: 責編: 時間:2024-06-24 17:19:23 177觀看
導(dǎo)讀ThreadLocal能夠在線程本地存儲對應(yīng)的變量,從而有效的避免線程安全問題。但是使用ThreadLocal時,稍微不注意就有可能造成內(nèi)存泄露的問題。那么ThreadLocal在哪些場景下會出現(xiàn)內(nèi)存泄露?哪些場景下不會出現(xiàn)內(nèi)存泄露?出現(xiàn)內(nèi)

ThreadLocal能夠在線程本地存儲對應(yīng)的變量,從而有效的避免線程安全問題。但是使用ThreadLocal時,稍微不注意就有可能造成內(nèi)存泄露的問題。

那么ThreadLocal在哪些場景下會出現(xiàn)內(nèi)存泄露?哪些場景下不會出現(xiàn)內(nèi)存泄露?出現(xiàn)內(nèi)存泄露的根本原因又是什么呢?如何真正避免內(nèi)存泄露?xsm28資訊網(wǎng)——每日最新資訊28at.com

接下來,我們就用大量的圖解來分析ThreadLocal內(nèi)存泄露的四個核心問題:哪些場景不會內(nèi)存泄露、哪些場景會內(nèi)存泄露、內(nèi)存泄露的根本原因是什么、以及如何真正 避免內(nèi)存泄露。xsm28資訊網(wǎng)——每日最新資訊28at.com

一、ThreadLocal內(nèi)部結(jié)構(gòu)

為了更好的說明ThreadLocal內(nèi)存泄露的場景,以及具體的原因,先來了解下ThreadLocal的內(nèi)部結(jié)構(gòu),如圖1所示。xsm28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片xsm28資訊網(wǎng)——每日最新資訊28at.com

xsm28資訊網(wǎng)——每日最新資訊28at.com

可以看到,ThreadLocal對象是存儲在每個Thread線程內(nèi)部的ThreadLocalMap中的,并且在ThreadLocalMap中有一個Entry數(shù)組,Entry數(shù)組中的每一個元素都是一個Entry對象。xsm28資訊網(wǎng)——每日最新資訊28at.com

每個Entry對象中存儲著一個ThreadLocal對象與其對應(yīng)的value值,每個Entry對象在Entry數(shù)組中的位置是通過ThreadLocal對象的threadLocalHashCode計算出來的,以此來快速定位Entry對象在Entry數(shù)組中的位置。xsm28資訊網(wǎng)——每日最新資訊28at.com

所以,在Thread中,可以存儲多個ThreadLocal對象。xsm28資訊網(wǎng)——每日最新資訊28at.com

二、不會出現(xiàn)內(nèi)存泄露的場景

了解完ThreadLocal的內(nèi)部存儲結(jié)構(gòu)后,我們先來思考下哪些場景下ThreadLocal不會發(fā)生內(nèi)存泄露,假設(shè)我們單獨開啟一個線程,并且將變量存儲到ThreadLocal中,如圖2所示。xsm28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片xsm28資訊網(wǎng)——每日最新資訊28at.com

可以看到,Thread線程在正常執(zhí)行的情況下,會引用ThreadLocalMap的實例對象,只要Thread線程一直在執(zhí)行任務(wù),這種引用關(guān)系就一直存在。xsm28資訊網(wǎng)——每日最新資訊28at.com

當Thread線程執(zhí)行任務(wù)結(jié)束退出時,Thread線程與ThreadLocalMap實例對象之間的引用關(guān)系就不存在了,如圖3所示。xsm28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片xsm28資訊網(wǎng)——每日最新資訊28at.com

Thread線程執(zhí)行完任務(wù)退出后,線程里持有的ThreadLocalMap對象也就失去了強引用,此時ThreadLocalMap對象就會被GC自動回收,而ThreadLocalMap中包含的ThreadLocal對象也會被GC回收掉,如圖4所示。xsm28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片xsm28資訊網(wǎng)——每日最新資訊28at.com

可以看出,如果只是通過Thread類或者Thread類的子類來創(chuàng)建線程執(zhí)行任務(wù),隨著對應(yīng)線程的任務(wù)執(zhí)行完畢,線程退出,Thread線程引用的ThreadLocal也會被GC回收掉,此時就不會出現(xiàn)內(nèi)存泄露的問題。xsm28資訊網(wǎng)——每日最新資訊28at.com

三、會出現(xiàn)內(nèi)存泄露的場景

在實際項目中,如果為每個任務(wù)的執(zhí)行都開啟一個線程的話,是非常耗費系統(tǒng)資源的,所以,在實際項目中,我們很少直接使用Thread類來創(chuàng)建線程,而是使用線程池來執(zhí)行對應(yīng)的任務(wù)。xsm28資訊網(wǎng)——每日最新資訊28at.com

如果是在線程池場景下,線程與ThreadLocalMap之間的引用關(guān)系又是怎樣的呢?這里,我們先來看一張圖,如圖5所示。xsm28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片xsm28資訊網(wǎng)——每日最新資訊28at.com

可以看到,線程池中會有多個線程執(zhí)行任務(wù),如果是通過ThreadLocal存儲數(shù)據(jù)的話,每個線程都會引用一個ThreadLocalMap對象。xsm28資訊網(wǎng)——每日最新資訊28at.com

另外,線程池中的核心線程在執(zhí)行完任務(wù)后,是不會退出的,可以循環(huán)使用,說明線程池中的每個核心線程和ThreadLocalMap之間一直是強引用關(guān)系,核心線程對應(yīng)的ThreadLocal是不會自動被GC回收的,會存在內(nèi)存泄露的風(fēng)險。xsm28資訊網(wǎng)——每日最新資訊28at.com

四、內(nèi)存泄露問題分析

這里,我們對在線程池中使用ThreadLocal存在內(nèi)存泄露問題的原因進行分析,首先,將ThreadLocalMap中的Entry數(shù)組展開,如圖6所示。xsm28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片xsm28資訊網(wǎng)——每日最新資訊28at.com

可以看到,ThreadLocalMap中包含一個Entry數(shù)組,而Entry數(shù)組中的每一個元素就是Entry對象,Entry對象中存儲的Key就是ThreadLocal對象,而value就是要存儲的數(shù)據(jù)。xsm28資訊網(wǎng)——每日最新資訊28at.com

其中,Entry對象中的Key屬于弱引用,這點我們可以從ThreadLocalMap類中的內(nèi)部類Entry的定義可以看出。Entry類的源碼詳見:java.lang.ThreadLocal.ThreadLocalMap.Entry。xsm28資訊網(wǎng)——每日最新資訊28at.com

static class Entry extends WeakReference<ThreadLocal<?>> {    /** The value associated with this ThreadLocal. */    Object value;    Entry(ThreadLocal<?> k, Object v) {        super(k);        value = v;    }}

可以看到,Entry類繼承了WeakReference類,WeakReference類的泛型是ThreadLocal,,說明ThreadLocalMap中的Entry數(shù)組對Entry對象的Key就是弱引用。xsm28資訊網(wǎng)——每日最新資訊28at.com

所以,Entry對象中的Key可以被GC自動回收。當Entry對象中的Key被GC自動回收后如圖7所示。xsm28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片xsm28資訊網(wǎng)——每日最新資訊28at.com

當Entry對象中的Key被GC自動回收后,對應(yīng)的ThreadLocal被GC回收掉了,變成了null,但是ThreadLocal對應(yīng)的value值依然被Entry引用,不能被GC自動回收,如圖8所示。xsm28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片xsm28資訊網(wǎng)——每日最新資訊28at.com

此時,我們可以看到,Entry對象中的Key,也就是ThreadLocal對象可以被GC自動回收,但是對應(yīng)的value還在被引用,所以,value是不能被GC自動回收的,這種情況下就會存在內(nèi)存泄露的風(fēng)險。xsm28資訊網(wǎng)——每日最新資訊28at.com

我們再來總結(jié)下,在線程池中使用ThreadLocal保存數(shù)據(jù)存在內(nèi)存泄露風(fēng)險的原因:線程池中的核心線程會被循環(huán)使用,每個線程中對應(yīng)的ThreadLocalMap會被線程強引用。xsm28資訊網(wǎng)——每日最新資訊28at.com

所以,每個線程對應(yīng)的ThreadLocalMap不能被GC自動回收。而ThreadLocalMap中包含一個Entry數(shù)組,Entry數(shù)組中含有多個Key為ThreadLocal,value為存儲的數(shù)據(jù)的Entry對象。xsm28資訊網(wǎng)——每日最新資訊28at.com

雖然Entry對象中的Key是弱引用,能夠被GC自動回收,但是value卻是強引用,不能被GC自動回收,所以,在線程池中使用ThreadLocal會存在內(nèi)存泄露的風(fēng)險。xsm28資訊網(wǎng)——每日最新資訊28at.com

五、如何避免內(nèi)存泄露

在線程池中使用ThreadLocal如何避免內(nèi)存泄露呢?ThreadLocal提供相應(yīng)的解決方法了嗎?這里,我們就從ThreadLocal的源碼中看看ThreadLocal是否提供了對應(yīng)的解決方案。xsm28資訊網(wǎng)——每日最新資訊28at.com

在ThreadLocal中,提供了一個remove()方法,源碼詳見:java.lang.ThreadLocal#remove。xsm28資訊網(wǎng)——每日最新資訊28at.com

public void remove() {    ThreadLocalMap m = getMap(Thread.currentThread());    if (m != null)        m.remove(this);}

可以看到,在remove()方法中,首先根據(jù)當前線程獲取ThreadLocalMap類型的m對象,不為空,則直接調(diào)用m對象的有參remove()方法移除value的值。xsm28資訊網(wǎng)——每日最新資訊28at.com

有參remove()方法的源碼詳見:java.lang.ThreadLocal.ThreadLocalMap#remove。xsm28資訊網(wǎng)——每日最新資訊28at.com

private void remove(ThreadLocal<?> key) {    Entry[] tab = table;    int len = tab.length;    int i = key.threadLocalHashCode & (len-1);    for (Entry e = tab[i];         e != null;         e = tab[i = nextIndex(i, len)]) {        if (e.get() == key) {            e.clear();            expungeStaleEntry(i);            return;        }    }}

可以看到,在有參remove()方法中,會通過threadLocalHashCode計算出Entry對象在Entry數(shù)組中的位置,并獲取出對應(yīng)的Entry對象。xsm28資訊網(wǎng)——每日最新資訊28at.com

如果Entry對象不為空,并且Entry對象中的Key等于傳入的ThreadLocal對象,則清除對應(yīng)的Key,并且調(diào)用expungeStaleEntry()方法。xsm28資訊網(wǎng)——每日最新資訊28at.com

接下來,我們再分析下expungeStaleEntry()方法,源碼詳見:java.lang.ThreadLocal.ThreadLocalMap#expungeStaleEntry。xsm28資訊網(wǎng)——每日最新資訊28at.com

private int expungeStaleEntry(int staleSlot) {    Entry[] tab = table;    int len = tab.length;    // expunge entry at staleSlot    tab[staleSlot].value = null;    tab[staleSlot] = null;    size--;    // Rehash until we encounter null    Entry e;    int i;    for (i = nextIndex(staleSlot, len);         (e = tab[i]) != null;         i = nextIndex(i, len)) {        ThreadLocal<?> k = e.get();        if (k == null) {            e.value = null;            tab[i] = null;            size--;        } else {            int h = k.threadLocalHashCode & (len - 1);            if (h != i) {                tab[i] = null;                // Unlike Knuth 6.4 Algorithm R, we must scan until                // null because multiple entries could have been stale.                while (tab[h] != null)                    h = nextIndex(h, len);                tab[h] = e;            }        }    }    return i;}

可以看到,在expungeStaleEntry()方法中,會將ThreadLocal為null對應(yīng)的value設(shè)置為null,同時會把對應(yīng)的Entry對象也設(shè)置為null,并且會將所有ThreadLocal對應(yīng)的value為null的Entry對象設(shè)置為null。xsm28資訊網(wǎng)——每日最新資訊28at.com

這樣就去除了強引用,便于后續(xù)的GC進行自動垃圾回收,也就避免了內(nèi)存泄露的問題。調(diào)用ThreadLocal的remove()方法后的示意圖如圖9所示。xsm28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片xsm28資訊網(wǎng)——每日最新資訊28at.com

注意:在ThreadLocal中,不僅僅是remove()方法會調(diào)用expungeStaleEntry()方法,在set()方法和get()方法中也可能會調(diào)用expungeStaleEntry()方法來清理數(shù)據(jù)。xsm28資訊網(wǎng)——每日最新資訊28at.com

還有一點需要注意的是,ThreadLocal雖然提供了避免內(nèi)存泄露的方法,但是ThreadLocal不會主動去執(zhí)行這些方法,需要我們在使用完ThreadLocal對象中保存的數(shù)據(jù)后,在finally{}代碼塊中調(diào)用ThreadLocal的remove()方法,加快GC自動垃圾回收,避免內(nèi)存泄露。xsm28資訊網(wǎng)——每日最新資訊28at.com

六、總結(jié)

本文,主要結(jié)合圖例介紹了ThreadLocal有關(guān)內(nèi)存泄露方面的知識,包括:ThreadLocal的內(nèi)部結(jié)構(gòu),不會出現(xiàn)內(nèi)存泄露的場景,會出現(xiàn)內(nèi)存泄露的場景,內(nèi)存泄露的問題分析以及如何避免內(nèi)存泄露。xsm28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-96059-0.html有沒有并發(fā)編程經(jīng)驗,一問這個類便知!

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 秒懂雙親委派機制

下一篇: 開源的 15 個優(yōu)秀 C# 項目及示例代碼

標簽:
  • 熱門焦點
  • 6月iOS設(shè)備性能榜:M2穩(wěn)居榜首 A系列只能等一手3nm來救

    沒有新品發(fā)布,自然iOS設(shè)備性能榜的上榜設(shè)備就沒有什么更替,僅僅只有跑分變化而產(chǎn)生的排名變動,畢竟蘋果新品的發(fā)布節(jié)奏就是這樣的,一年下來也就幾個移動端新品,不會像安卓廠商,一
  • 十個可以手動編寫的 JavaScript 數(shù)組 API

    JavaScript 中有很多API,使用得當,會很方便,省力不少。 你知道它的原理嗎? 今天這篇文章,我們將對它們進行一次小總結(jié)。現(xiàn)在開始吧。1.forEach()forEach()用于遍歷數(shù)組接收一參
  • 谷歌KDD'23工作:如何提升推薦系統(tǒng)Ranking模型訓(xùn)練穩(wěn)定性

    谷歌在KDD 2023發(fā)表了一篇工作,探索了推薦系統(tǒng)ranking模型的訓(xùn)練穩(wěn)定性問題,分析了造成訓(xùn)練穩(wěn)定性存在問題的潛在原因,以及現(xiàn)有的一些提升模型穩(wěn)定性方法的不足,并提出了一種新
  • 破圈是B站頭上的緊箍咒

    來源 | 光子星球撰文 | 吳坤諺編輯 | 吳先之每年的暑期檔都少不了瞄準追劇女孩們的古偶劇集,2021年有優(yōu)酷的《山河令》,2022年有愛奇藝的《蒼蘭訣》,今年卻輪到小破站抓住了追
  • “又被陳思誠騙了”

    作者|張思齊 出品|眾面(ID:ZhongMian_ZM)如今的國產(chǎn)懸疑電影,成了陳思誠的天下。最近大爆電影《消失的她》票房突破30億斷層奪魁暑期檔,陳思誠再度風(fēng)頭無兩。你可以說陳思誠的
  • ESG的面子與里子

    來源 | 光子星球撰文 | 吳坤諺編輯 | 吳先之三伏大幕拉起,各地高溫預(yù)警不絕,但處于厄爾尼諾大&ldquo;烤&rdquo;之下的除了眾生,還有各大企業(yè)發(fā)布的ESG報告。ESG是&ldquo;環(huán)境保
  • OPPO K11搭載長壽版100W超級閃充:26分鐘充滿100%

    據(jù)此前官方宣布,OPPO將于7月25日也就是今天下午14:30舉辦新品發(fā)布會,屆時全新的OPPO K11將正式與大家見面,將主打旗艦影像,和同檔位競品相比,其最大的賣
  • Windows 11發(fā)布,微軟一改往常對老機型開放的態(tài)度

    距離 Windows 11 發(fā)布已經(jīng)過去一周,在過去一周里,很多數(shù)碼愛好者圍繞其對 Android 應(yīng)用的支持、對老機型的升級問題展開了激烈討論。與以往不同的是,在這次大
  • 最薄的14英寸游戲筆記本電腦 Alienware X14已可以購買

    2022年1月份在國際消費電子展(CES2022)上首次亮相的Alienware新品——Alienware X14現(xiàn)在已經(jīng)可以購買了,這款筆記本電腦被譽為世界上最薄的 14 英寸游戲筆
Top 主站蜘蛛池模板: 通州市| 宜春市| 格尔木市| 西盟| 阿巴嘎旗| 嘉荫县| 称多县| 柯坪县| 沅陵县| 濉溪县| 林芝县| 林州市| 张家港市| 灵丘县| 桃江县| 庆安县| 巫山县| 两当县| 绩溪县| 松滋市| 延安市| 英吉沙县| 瓦房店市| 莱州市| 灌阳县| 应城市| 泗阳县| 疏勒县| 荃湾区| 长垣县| 延吉市| 石城县| 宁城县| 娄烦县| 自贡市| 龙胜| 江川县| 亳州市| 都江堰市| 开封市| 苗栗县|