自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

ThreadLocal真的會(huì)造成內(nèi)存泄漏嗎?

開(kāi)發(fā) 前端
在多線程并發(fā)訪問(wèn)同一個(gè)共享變量的情況下,如果不做同步控制的話,就可能會(huì)導(dǎo)致數(shù)據(jù)不一致的問(wèn)題,所以,我們需要使用synchronized加鎖來(lái)解決。

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

1、ThreadLocal的基本原理

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

而ThreadLocal換了一個(gè)思路來(lái)處理多線程的情況。

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

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

2、四種對(duì)象引用

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. 調(diào)用set()方法時(shí),ThreadLocal會(huì)進(jìn)行采樣清理、全量清理,擴(kuò)容時(shí)還會(huì)繼續(xù)檢查。
  2. 調(diào)用get()方法時(shí),如果沒(méi)有直接命中或者向后環(huán)形查找時(shí)也會(huì)進(jìn)行清理。
  3. 調(diào)用remove()時(shí),除了清理當(dāng)前Entry,還會(huì)向后繼續(xù)清理。
責(zé)任編輯:姜華 來(lái)源: Tom彈架構(gòu)
相關(guān)推薦

2016-10-31 20:56:57

Javascript閉包內(nèi)存泄漏

2025-04-01 05:22:00

JavaThread變量

2018-10-25 15:24:10

ThreadLocal內(nèi)存泄漏Java

2021-08-10 09:58:59

ThreadLocal內(nèi)存泄漏

2020-09-10 07:40:28

ThreadLocal內(nèi)存

2022-09-22 13:56:56

線程Java

2024-03-22 13:31:00

線程策略線程池

2021-02-18 16:53:44

內(nèi)存ThreadLocal線程

2024-09-29 08:57:25

2022-10-18 08:38:16

內(nèi)存泄漏線程

2023-03-01 09:39:05

2021-04-23 07:27:31

內(nèi)存分配CPU

2022-03-25 09:39:50

LinuxLinux top

2022-04-07 07:41:18

String字符串內(nèi)存泄漏

2023-05-29 07:17:48

內(nèi)存溢出場(chǎng)景

2018-11-20 09:37:19

Java內(nèi)存模型

2021-06-02 07:57:48

內(nèi)存管理

2021-07-13 06:42:58

JavaEquals方法

2024-03-11 08:22:40

Java內(nèi)存泄漏

2023-12-18 10:45:23

內(nèi)存泄漏計(jì)算機(jī)服務(wù)器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)