精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何使用ThreadLocal來避免內存泄漏

5jek_harmonyos ? 來源:CSDN博客 ? 作者:pony-zi ? 2021-08-20 09:29 ? 次閱讀

本次給大家介紹重要的工具ThreadLocal。講解內容如下,同時介紹什么場景下發生內存泄漏,如何復現內存泄漏,如何正確使用它來避免內存泄漏。

ThreadLocal是什么?有哪些用途?

ThreadLocal如何使用

ThreadLocal原理

ThreadLocal使用有哪些坑及注意事項

Part1ThreadLocal是什么?有哪些用途?

首先介紹Thread類中屬性threadLocals:

/* ThreadLocal values pertaining to this thread.

This map is maintained * by the ThreadLocal class. */

ThreadLocal.ThreadLocalMap threadLocals = null;

我們發現Thread并沒有提供成員變量threadLocals的設置與訪問的方法,那么每個線程的實例threadLocals參數我們如何操作呢?這時我們的主角:ThreadLocal就登場了。

所以有那么一句總結:

ThreadLocal是線程Thread中屬性threadLocals的管理者。

也就是說我們對于ThreadLocal的get, set,remove的操作結果都是針對當前線程Thread實例的threadLocals存,取,刪除操作。類似于一個開發者的任務,產品經理左右不了,產品經理只能通過技術leader來給開發者分配任務。

下面再舉個栗子,進一步說明他們之間的關系:

1. 每個人都一張銀行卡

每個人每張卡都有一定的余額。

每個人獲取銀行卡余額都必須通過該銀行的管理系統。

每個人都只能獲取自己卡持有的余額信息,他人的不可訪問。

映射到我們要說的ThreadLocal

card類似于Thread

card余額屬性,卡號屬性等類似于Treadlocal內部屬性集合threadLocals

cardManager類似于ThreadLocal管理類

那ThreadLocal有哪些應用場景呢?

其實我們無意間已經時時刻刻在使用ThreadLocal提供的便利,如果說多數據源的切換你比較陌生,那么spring提供的聲明式事務就再熟悉不過了,我們在研發過程中無時無刻不在使用,而spring聲明式事務的重要實現基礎就是ThreadLocal,只不過大家沒有去深入研究spring聲明式事務的實現機制。后面有機會我會給大家介紹spring聲明式事務的原理及實現機制。

原來ThreadLocal這么強大,但應用開發者使用較少,同時有些研發人員對于ThreadLocal內存泄漏,等潛在問題,不敢試用,恐怕這是對于ThreadLocal最大的誤解,后面我們將會仔細分析,只要按照正確使用方式,就沒什么問題。如果ThreadLocal存在問題,豈不是spring聲明式事務是我們程序最大的潛在危險嗎?

Part2ThreadLocal如何使用

為了更直觀的體會ThreadLocal的使用我們假設如下場景

我們給每個線程生成一個ID。

一旦設置,線程生命周期內不可變化。

容器活動期間不可以生成重復的ID

我們創建一個ThreadLocal管理類:

2981b0cc-013e-11ec-9bcf-12bb97331649.png

測試程序如下:我們同一個線程不斷get,測試id是否變化,同時測試完成后我們就將其釋放掉。

29adbec4-013e-11ec-9bcf-12bb97331649.png

在主程序中我們開啟多個線程測試不通線程之間是否會影響

29cdd862-013e-11ec-9bcf-12bb97331649.jpg

不出意外我們的結果為:

2a1f53c2-013e-11ec-9bcf-12bb97331649.jpg

結果:確實是不同線程間id不同,相同線程id相同。

Part3ThreadLocal原理

①ThreadLocal類結構及方法解析:

2a5b56b0-013e-11ec-9bcf-12bb97331649.png

上圖可知:ThreadLocal三個方法get, set , remove以及內部類ThreadLocalMap

②ThreadLocal及Thread之間的關系:

2a8604a0-013e-11ec-9bcf-12bb97331649.png

從這張圖我們可以直觀的看到Thread中屬性threadLocals,作為一個特殊的Map,它的key值就是我們ThreadLocal實例,而value值這是我們設置的值。

③ThreadLocal的操作過程:

我們以get方法為例:

2aa836e2-013e-11ec-9bcf-12bb97331649.png

其中getMap(t)返回的就上當前線程的threadlocals,如下圖,然后根據當前ThreadLocal實例對象作為key獲取ThreadLocalMap中的value,如果首次進來這調用setInitialValue()

2ac868d6-013e-11ec-9bcf-12bb97331649.png

2af774aa-013e-11ec-9bcf-12bb97331649.png

set的過程也類似:

2b14afa2-013e-11ec-9bcf-12bb97331649.png

注意:ThreadLocal中可以直接t.threadLocals是因為Thread與ThreadLocal在同一個包下,同樣Thread可以直接訪問ThreadLocal.ThreadLocalMap threadLocals = null;來進行聲明屬性。另外,歡迎關注公眾號Java筆記蝦,后臺回復“后端面試”,送你一份面試題寶典!

Part4ThreadLocal使用有哪些坑及注意事項

我經常在網上看到駭人聽聞的標題,ThreadLocal導致內存泄漏,這通常讓一些剛開始對ThreadLocal理解不透徹的開發者,不敢貿然使用。越不用,越陌生。這樣就讓我們錯失了更好的實現方案,所以敢于引入新技術,敢于踩坑,才能不斷進步。

我們來看下為什么說ThreadLocal會引起內存泄漏,什么場景下會導致內存泄漏?

先回顧下什么叫內存泄漏,對應的什么叫內存溢出

Memory overflow:內存溢出,沒有足夠的內存提供申請者使用。

Memory leak:內存泄漏,程序申請內存后,無法釋放已申請的內存空間,內存泄漏的堆積終將導致內存溢出。

顯然是TreadLocal在不規范使用的情況下導致了內存沒有釋放。

2b9a3816-013e-11ec-9bcf-12bb97331649.png

紅框里我們看到了一個特殊的類WeakReference,同樣這個類,應用開發者也同樣很少使用,這里簡單介紹下吧

2bd74076-013e-11ec-9bcf-12bb97331649.jpg

既然WeakReference在下一次gc即將被回收,那么我們的程序為什么沒有出問題呢?

①所以我們測試下弱引用的回收機制:

2beedec0-013e-11ec-9bcf-12bb97331649.png

這一種存在強引用不會被回收。

2c12f152-013e-11ec-9bcf-12bb97331649.png

這里沒有強引用將會被回收。

上面演示了弱引用的回收情況,下面我們看下ThreadLocal的弱引用回收情況。

②ThreadLocal的弱引用回收情況

2c36b47a-013e-11ec-9bcf-12bb97331649.jpg

如上圖所示,我們在作為key的ThreadLocal對象沒有外部強引用,下一次gc必將產生key值為null的數據,若線程沒有及時結束必然出現,一條強引用鏈Threadref–》Thread–》ThreadLocalMap–》Entry,所以這將導致內存泄漏。

下面我們模擬復現ThreadLocal導致內存泄漏:

1.為了效果更佳明顯我們將我們的treadlocals的存儲值value設置為1萬字符串的列表:

class ThreadLocalMemory {

// Thread local variable containing each thread‘s ID

public ThreadLocal《List《Object》》 threadId = new ThreadLocal《List《Object》》() {

@Override

protected List《Object》 initialValue() {

List《Object》 list = new ArrayList《Object》();

for (int i = 0; i 《 10000; i++) {

list.add(String.valueOf(i));

}

return list;

}

};

// Returns the current thread’s unique ID, assigning it if necessary

public List《Object》 get() {

return threadId.get();

}

// remove currentid

public void remove() {

threadId.remove();

}

}

測試代碼如下:

public static void main(String[] args)

throws InterruptedException {

// 為了復現key被回收的場景,我們使用臨時變量

ThreadLocalMemory memeory = new ThreadLocalMemory();

// 調用

incrementSameThreadId(memeory);

System.out.println(“GC前:key:” + memeory.threadId);

System.out.println(“GC前:value-size:” + refelectThreadLocals(Thread.currentThread()));

// 設置為null,調用gc并不一定觸發垃圾回收,但是可以通過java提供的一些工具進行手工觸發gc回收。

memeory.threadId = null;

System.gc();

System.out.println(“GC后:key:” + memeory.threadId);

System.out.println(“GC后:value-size:” + refelectThreadLocals(Thread.currentThread()));

// 模擬線程一直運行

while (true) {

}

}

此時我們如何知道內存中存在memory leak呢?

我們可以借助jdk提供的一些命令dump當前堆內存,命令如下:

jmap -dump:live,format=b,file=heap.bin 《pid》

然后我們借助MAT可視化分析工具,來查看對內存,分析對象實例的存活狀態:

首先打開我們工具提示我們的內存泄漏分析:

這里我們可以確定的是ThreadLocalMap實例的Entry.value是沒有被回收的。

最后我們要確定Entry.key是否還在?打開Dominator Tree,搜索我們的ThreadLocalMemory,發現并沒有存活的實例。

以上我們復現了ThreadLocal不正當使用,引起的內存泄漏。

文中源碼:

https://github.com/z-one/basictest/tree/master/src/main/java/com/spring/test/threadlocal

所以我們總結了使用ThreadLocal時會發生內存泄漏的前提條件:

ThreadLocal引用被設置為null,且后面沒有set,get,remove操作。

線程一直運行,不停止。(線程池)

觸發了垃圾回收。(Minor GC或Full GC)

我們看到ThreadLocal出現內存泄漏條件還是很苛刻的,所以我們只要破壞其中一個條件就可以避免內存泄漏,單但為了更好的避免這種情況的發生我們使用ThreadLocal時遵守以下兩個小原則:

①ThreadLocal申明為private static final。

Private與final 盡可能不讓他人修改變更引用,

Static 表示為類屬性,只有在程序結束才會被回收。

②ThreadLocal使用后務必調用remove方法。

最簡單有效的方法是使用后將其移除。

責任編輯:haq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    3002

    瀏覽量

    73883
  • 內存泄露
    +關注

    關注

    0

    文章

    6

    瀏覽量

    1978

原文標題:ThreadLocal理解, 運用以及內存泄漏的處理方案

文章出處:【微信號:harmonyos_developer,微信公眾號:harmonyos_developer】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    ThreadLocal實例應用

    ThreadLocal相信大家都用過,但你知道他的原理嗎,今天了不起帶大家學習ThreadLocalThreadLocal是什么 在多線程編程中,經常會遇到需要在不同線程中共享數據的情況
    的頭像 發表于 09-30 10:19 ?639次閱讀
    <b class='flag-5'>ThreadLocal</b>實例應用

    ThreadLocal的定義、用法及優點

    ThreadLocal 簡介 ThreadLocal是Java中一個非常重要的線程技術。它可以讓每個線程都擁有自己的變量副本,避免了線程間的競爭和數據泄露問題。在本文中,我們將詳細介紹
    的頭像 發表于 09-30 10:14 ?1001次閱讀
    <b class='flag-5'>ThreadLocal</b>的定義、用法及優點

    內存泄漏定位該如何去實現呢

    。對于內存泄漏的情況,如果一開始不做預防,定位內存泄漏就會相當繁瑣,定位也會很長,非常的耗時、耗力。這里可通過malloc、free的第二次封裝
    發表于 12-17 07:24

    ThreadLocal發生內存泄漏的原因

    ,就可能會導致內存泄漏。下面,我們將圍繞三個方面分析 ThreadLocal 內存泄漏的問題
    的頭像 發表于 05-05 16:23 ?3657次閱讀

    內存泄漏的特點和類型

    在計算機科學中,內存泄漏(memory leak)指由于疏忽或錯誤使程序未能釋放而造成不能再使用的內存的情況。內存泄漏并非指
    的頭像 發表于 06-20 10:58 ?2793次閱讀

    內存泄漏問題原理及檢視方法

    可能不少開發者都遇到過內存泄漏導致的網上問題,具體表現為單板在現網運行數月以后,因為內存耗盡而導致單板復位現象。一方面,內存泄漏問題屬于比較
    的頭像 發表于 10-10 10:42 ?2511次閱讀

    如何避免內存泄漏的方法和原則

    本文向讀者介紹了如何避免內存泄漏的方法和原則,在細節和大體方向上均給出一些可行性方案。讀者可以嘗試文中提出的方法,改進自己的代碼,大大減少內存泄漏
    的頭像 發表于 10-21 14:30 ?5872次閱讀
    如何<b class='flag-5'>避免</b><b class='flag-5'>內存</b><b class='flag-5'>泄漏</b>的方法和原則

    什么是內存泄漏內存泄漏有哪些現象

    內存泄漏幾乎是很難避免的,不管是老手還是新手,都存在這個問題,甚至 Windows 與 Linux 這類系統軟件也或多或少存在著內存泄漏
    的頭像 發表于 09-05 17:24 ?9612次閱讀

    ThreadLocal基本內容與用法

    下面我們就來看看道哥都用的ThreadLocal。 1 ThreadLocal你來自哪里 Since : 1.2 Author : Josh Bloch and Doug Lea 又是并發大佬們
    的頭像 發表于 10-13 11:39 ?435次閱讀

    什么是內存泄漏?如何避免JavaScript內存泄漏

    JavaScript 代碼中常見的內存泄漏的常見來源: 研究內存泄漏問題就相當于尋找符合垃圾回收機制的編程方式,有效避免對象引用的問題。
    發表于 10-27 11:30 ?361次閱讀
    什么是<b class='flag-5'>內存</b><b class='flag-5'>泄漏</b>?如何<b class='flag-5'>避免</b>JavaScript<b class='flag-5'>內存</b><b class='flag-5'>泄漏</b>

    內存泄漏如何避免

    的數,那就是內存溢出。 2. 內存泄漏 內存泄露 memory leak,是指程序在申請內存后,無法釋放已申請的
    的頭像 發表于 11-10 11:04 ?707次閱讀
    <b class='flag-5'>內存</b><b class='flag-5'>泄漏</b>如何<b class='flag-5'>避免</b>

    內存泄漏會產生哪些后果

    內存泄漏原因 內存泄漏在C/C++這種不帶GC(Garbage Collection)的語言里,是一個經常發生的問題。因為沒有GC,所以分配的內存
    的頭像 發表于 11-10 15:06 ?761次閱讀
    <b class='flag-5'>內存</b><b class='flag-5'>泄漏</b>會產生哪些后果

    線程內存泄漏問題的定位

    記錄一個關于線程內存泄漏問題的定位過程,以及過程中的收獲。 1. 初步定位 是否存在內存泄漏:想到內存
    的頭像 發表于 11-13 11:38 ?583次閱讀
    線程<b class='flag-5'>內存</b><b class='flag-5'>泄漏</b>問題的定位

    內存溢出與內存泄漏:定義、區別與解決方案

    內存溢出與內存泄漏:定義、區別與解決方案? 內存溢出和內存泄漏是計算機科學中常見的問題,在開發和
    的頭像 發表于 12-19 14:10 ?2474次閱讀

    C語言內存泄漏問題原理

    內存泄漏問題只有在使用堆內存的時候才會出現,棧內存不存在內存泄漏問題,因為棧
    發表于 03-19 11:38 ?482次閱讀
    C語言<b class='flag-5'>內存</b><b class='flag-5'>泄漏</b>問題原理