日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
ThreadLocal真的會造成內(nèi)存泄漏嗎?

ThreadLoca在并發(fā)場景中,應(yīng)用非常多。前幾天有位小伙伴問我一個問題,說ThreadLocal是不是真的會造成內(nèi)存泄漏?今天給大家做一個分享。

成都創(chuàng)新互聯(lián)專注于寬城企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站,電子商務(wù)商城網(wǎng)站建設(shè)。寬城網(wǎng)站建設(shè)公司,為寬城等地區(qū)提供建站服務(wù)。全流程專業(yè)公司,專業(yè)設(shè)計,全程項目跟蹤,成都創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)

1、ThreadLocal的基本原理

考慮到很多小伙伴可能還不太了解ThreadLocal,我先簡單介紹一下ThreadLocal。在多線程并發(fā)訪問同一個共享變量的情況下,如果不做同步控制的話,就可能會導(dǎo)致數(shù)據(jù)不一致的問題,所以,我們需要使用synchronized加鎖來解決。

而ThreadLocal換了一個思路來處理多線程的情況。

ThreadLocal本身并不存儲數(shù)據(jù),它使用了線程中的threadLocals屬性,threadLocals的類型就是在ThreadLocal中的定義的ThreadLocalMap對象,當(dāng)調(diào)用ThreadLocal的set(T value)方法時,ThreadLocal將自身的引用也就是this作為Key,然后,把用戶傳入的值作為Value存儲到線程的ThreadLocalMap中,這就相當(dāng)于每個線程的讀寫操作都是基于線程自身的一個私有副本,線程之間的數(shù)據(jù)是相互隔離的,互不影響。

這樣一來基于ThreadLocal的操作也就不存在線程安全問題了。它相當(dāng)于采用了用空間來換時間的思路,從而提高程序的執(zhí)行效率。

2、四種對象引用

在ThreadLocalMap內(nèi)部,維護(hù)了一個Entry數(shù)組table的屬性,用來存儲鍵值對的映射關(guān)系,來看這樣一段代碼片段:

static class ThreadLocalMap {
...
private Entry[] table;
static class Entry implements WeakReference> {
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
...
}

Entry將ThreadLocal作為Key,值作為Value保存,它繼承自WeakReference,注意構(gòu)造函數(shù)里的第一行代碼super(k),這意味著ThreadLocal對象是一個「弱引用」。有的小伙伴可能對「弱引用」不太熟悉,這里再介紹一下Java的四種引用關(guān)系。

在JDK1.2之后,Java對引用的概念做了一些擴(kuò)充,將引用分為“強(qiáng)”、“軟”、“弱”、“虛”四種,由強(qiáng)到弱依次為:

強(qiáng)引用:指代碼中普遍存在的賦值行為,如:Object o = new Object(),只要強(qiáng)引用關(guān)系還在,對象就永遠(yuǎn)不會被回收。

軟引用:還有用處,但不是必須存活的對象,JVM會在內(nèi)存溢出前對其進(jìn)行回收,例如:緩存。

弱引用:非必須存活的對象,引用關(guān)系比軟引用還弱,不管內(nèi)存是否夠用,下次GC一定回收。

虛引用:也稱“幽靈引用”、“幻影引用”,最弱的引用關(guān)系,完全不影響對象的回收,等同于沒有引用,虛引用的唯一的目的是對象被回收時會收到一個系統(tǒng)通知。

這個描述還是比較官方的,簡單總結(jié)一下,大家應(yīng)該都追過劇,強(qiáng)引用就好比是男主角,怎么都死不了。軟引用就像女主角,雖有一段經(jīng)歷,還是沒走到最后。弱引用就是男二號,注定用來犧牲的。虛引用就是路人甲了。

3、造成內(nèi)存泄漏的原因

內(nèi)存泄漏和ThreadLocalMap中定義的Entry類有非常大的關(guān)系。

這個動畫完整地展示了ThreadLocal中對象引用的關(guān)系,需要這張高清圖的小伙伴可以在評論區(qū)留言。

由于ThreadLocal對象是弱引用,如果外部沒有強(qiáng)引用指向它,它就會被GC回收,導(dǎo)致Entry的Key為空(null),如果這時Value外部也沒有強(qiáng)引用指向它,那么Value就永遠(yuǎn)也訪問不到了,按理也應(yīng)該被GC回收,但是由于Entry對象還在強(qiáng)引用Value,導(dǎo)致Value無法被回收,這時「內(nèi)存泄漏」就發(fā)生了,Value成了一個永遠(yuǎn)也無法被訪問,但是又無法被回收的對象。

Entry對象屬于ThreadLocalMap,ThreadLocalMap又屬于Thread,如果線程本身的生命周期很短,短時間內(nèi)就會被銷毀,那么「內(nèi)存泄漏」立刻就會得到解決,只要線程被銷毀,Value也會隨之被回收。

問題是,線程本身是非常珍貴的計算機(jī)資源,很少會去頻繁的創(chuàng)建和銷毀,一般都是通過線程池來使用,這就將線程的生命周期大大拉長,「內(nèi)存泄漏」的影響也會越來越大。

最后,一句話總結(jié)一下。

threadLocals對象中的Entry對象不再使用后,如果沒有及時清除Entry對象 ,而程序自身也無法通過垃圾回收機(jī)制自動清除,就可能導(dǎo)致內(nèi)存泄漏。

4、如何避免內(nèi)存泄漏?

不要聽到「內(nèi)存泄漏」就不敢使用ThreadLocal,只要規(guī)范化使用是不會有問題的。我給大家支幾個招:

  1. 每次使用完ThreadLocal都記得調(diào)用remove()方法清除數(shù)據(jù)。
  2. 將ThreadLocal變量盡可能地定義成static final,避免頻繁創(chuàng)建ThreadLocal實例。這樣也就保證程序一直存在ThreadLocal的強(qiáng)引用,也能保證任何時候都能通過ThreadLocal的弱引用訪問到Entry的Value值,進(jìn)而清除掉。

當(dāng)然,就是使用不規(guī)范,ThreadLocal內(nèi)部也做了一些優(yōu)化,比如:

  1. 調(diào)用set()方法時,ThreadLocal會進(jìn)行采樣清理、全量清理,擴(kuò)容時還會繼續(xù)檢查。
  2. 調(diào)用get()方法時,如果沒有直接命中或者向后環(huán)形查找時也會進(jìn)行清理。
  3. 調(diào)用remove()時,除了清理當(dāng)前Entry,還會向后繼續(xù)清理。

分享題目:ThreadLocal真的會造成內(nèi)存泄漏嗎?
文章網(wǎng)址:http://www.5511xx.com/article/dhjcdgd.html