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

ThreadLocal 你怎么動(dòng)不動(dòng)就內(nèi)存泄漏?

存儲(chǔ) 存儲(chǔ)軟件
ThreadLocal 解決了什么問題呢?它是為了解決對(duì)象不能被多線程共享訪問的問題,通過 threadLocal.set() 方法將對(duì)象實(shí)例保存在每個(gè)線程自己所擁有的 threadLocalMap 中,這樣的話每個(gè)線程都使用自己的對(duì)象實(shí)例,彼此不會(huì)影響從而達(dá)到了隔離的作用,這樣就解決了對(duì)象在被共享訪問時(shí)帶來的線程安全問題。

[[341471]]

本文轉(zhuǎn)載自微信公眾號(hào)「Java極客技術(shù)」,作者鴨血粉絲。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java極客技術(shù)公眾號(hào)。  

如果說 ThreadLocal 的話,那肯定就會(huì)涉及到內(nèi)存泄漏,為啥嘞

因?yàn)?吧啦吧啦 ~

ThreadLocal 解決了什么問題呢?

它是為了解決對(duì)象不能被多線程共享訪問的問題,通過 threadLocal.set() 方法將對(duì)象實(shí)例保存在每個(gè)線程自己所擁有的 threadLocalMap 中,這樣的話每個(gè)線程都使用自己的對(duì)象實(shí)例,彼此不會(huì)影響從而達(dá)到了隔離的作用,這樣就解決了對(duì)象在被共享訪問時(shí)帶來的線程安全問題。

啥意思呢?打個(gè)比方,現(xiàn)在公司所有人都要填寫一個(gè)表格,但是只有一支筆,這個(gè)時(shí)候就只能上個(gè)人用完了之后,下個(gè)人才可以使用,為了保證"筆"這個(gè)資源的可用性,只需要保證在接下來每個(gè)人的獲取順序就可以了,這就是 lock 的作用,當(dāng)這支筆被別人用的時(shí)候,我就加 lock ,你來了那就進(jìn)入隊(duì)列排隊(duì)等待獲取資源(非公平方式那就另外說了),這支筆用完之后就釋放 lock ,然后按照順序給下個(gè)人使用。

但是完全可以一個(gè)人一支筆對(duì)不對(duì),這樣的話,你填寫你的表格,我填寫我的表格,咱倆誰(shuí)都不耽擱誰(shuí)。這就是 ThreadLocal 在做的事情,因?yàn)槊總€(gè) Thread 都有一個(gè)副本,就不存在資源競(jìng)爭(zhēng),所以也就不需要加鎖,這不就是拿空間去換了時(shí)間嘛!

在開始之前,咱們先把 Thread, ThreadLocal, ThreadLocalMap 的關(guān)系捋一捋:

 

可以看到,在 Thread 中持有一個(gè) ThreadLocalMap , ThreadLocalMap 又是由 Entry 來組成的,在 Entry 里面有 ThreadLocal 和 value

ThreadLocal 為啥動(dòng)不動(dòng)就內(nèi)存泄漏呢?

在這里先給個(gè)解釋,后面咱們?cè)僭敿?xì)分析:

首先是因?yàn)?ThreadLocal 是基于 ThreadLocalMap 實(shí)現(xiàn)的,其中 ThreadLocalMap 的 Entry 繼承了 WeakReference ,而 Entry 對(duì)象中的 key 使用了 WeakReference 封裝,也就是說, Entry 中的 key 是一個(gè)弱引用類型,對(duì)于弱引用來說,它只能存活到下次 GC 之前

如果此時(shí)一個(gè)線程調(diào)用了 ThreadLocalMap 的 set 設(shè)置變量,當(dāng)前的 ThreadLocalMap 就會(huì)新增一條記錄,但由于發(fā)生了一次垃圾回收,這樣就會(huì)造成一個(gè)結(jié)果: key 值被回收掉了,但是 value 值還在內(nèi)存中,而且如果線程一直存在的話,那么它的 value 值就會(huì)一直存在

這樣被垃圾回收掉的 key 就會(huì)一直存在一條引用鏈: Thread -> ThreadLocalMap -> Entry -> Value :

 

就是因?yàn)檫@條引用鏈的存在,就會(huì)導(dǎo)致如果 Thread 還在運(yùn)行,那么 Entry 不會(huì)被回收,進(jìn)而 value 也不會(huì)被回收掉,但是 Entry 里面的 key 值已經(jīng)被回收掉了

這只是一個(gè)線程,如果再來一個(gè)線程,又來一個(gè)線程…多了之后就會(huì)造成內(nèi)存泄漏

知道是怎么造成內(nèi)存泄漏之后,接下來要做的事情就好說了,不是因?yàn)?value 值沒有被回收掉所以才會(huì)導(dǎo)致內(nèi)存泄露的嘛

那使用完 key 值之后,將 value 值通過 remove 方法 remove 掉,這樣的話內(nèi)存中就不會(huì)有 value 值了,也就防止了內(nèi)存泄漏嘛

ThreadLocal 是基于 ThreadLocalMap 實(shí)現(xiàn)的?

OK ,上面的內(nèi)容講完了,接下來一一來看

首先,你怎么知道 ThreadLocal 是基于 ThreadLocalMap 實(shí)現(xiàn)的呢?

從源碼知道的~

在源碼中能夠看到下面這幾行代碼:

  1. public class ThreadLocal<T> { 
  2.     static class ThreadLocalMap { 
  3.         static class Entry extends WeakReference<ThreadLocal<?>> { 
  4.             /** The value associated with this ThreadLocal. */ 
  5.             Object value; 
  6.  
  7.             Entry(ThreadLocal<?> k, Object v) { 
  8.                 super(k); 
  9.                 value = v; 
  10.             } 
  11.         } 
  12.     } 

代碼中說的很清楚了,在 ThreadLocal 內(nèi)部維護(hù)著 ThreadLocalMap ,而它的 Entry 則繼承自 WeakReference 的 ThreadLocal ,其中 Entry 的 k 為 ThreadLocal , v 為 Object ,在調(diào)用 super(k) 時(shí)就將 ThreadLocal 實(shí)例包裝成了一個(gè) WeakReference

強(qiáng)弱引用這塊內(nèi)容阿粉就直接放一個(gè)表格吧:

引用類型 功能特點(diǎn)
強(qiáng)引用 ( Strong Reference ) 被強(qiáng)引用關(guān)聯(lián)的對(duì)象永遠(yuǎn)不會(huì)被垃圾回收器回收掉
軟引用( Soft Reference ) 軟引用關(guān)聯(lián)的對(duì)象,只有當(dāng)系統(tǒng)將要發(fā)生內(nèi)存溢出時(shí),才會(huì)去回收軟引用引用的對(duì)象
弱引用 ( Weak Reference ) 只被弱引用關(guān)聯(lián)的對(duì)象,只要發(fā)生垃圾收集事件,就會(huì)被回收
虛引用 ( Phantom Reference ) 被虛引用關(guān)聯(lián)的對(duì)象的唯一作用是能在這個(gè)對(duì)象被回收器回收時(shí)收到一個(gè)系統(tǒng)通知

從表格中應(yīng)該能夠看出來,弱引用的對(duì)象只要發(fā)生垃圾收集事件,就會(huì)被回收

所以弱引用的存活時(shí)間也就是下次 GC 之前了

在這里阿粉就有個(gè)問題想問問了:為什么 ThreadLocal 采用弱引用,而不是強(qiáng)引用嘞?

在 ThreadLocalMap 上面有些注釋,我在這里摘錄一部分,或許可以從中窺探一二:

To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys

翻譯一下就是:(雖然我英語(yǔ)不是很好

為了解決非常大且長(zhǎng)期使用的問題,哈希表使用了弱引用的 key

假設(shè),假設(shè), ThreadLocal 使用的是強(qiáng)引用,會(huì)怎樣呢?

如果是強(qiáng)引用的話,在表格中也能夠看出來,被強(qiáng)引用關(guān)聯(lián)的對(duì)象,永遠(yuǎn)都不會(huì)被垃圾回收器回收掉

如果引用的 ThreadLocal 對(duì)象被回收了,但是 ThreadLocalMap 還持有對(duì) ThreadLocal 的強(qiáng)引用,如果沒有 remove 的話, 在 GC 時(shí)進(jìn)行可達(dá)性分析, ThreadLocal 依然可達(dá),這樣就不會(huì)對(duì) ThreadLocal 進(jìn)行回收,但是我們期望的是引用的 ThreadLocal 對(duì)象被回收,這樣不就達(dá)不到目的了嘛

使用弱引用的話,雖然會(huì)出現(xiàn)內(nèi)存泄漏的問題,但是在 ThreadLocal 生命周期里面,都有對(duì) key 值為 null 時(shí)進(jìn)行回收的處理操作

所以,使用弱引用的話,可以在 ThreadLocal 生命周期中盡可能保證不出現(xiàn)內(nèi)存泄漏的問題

 

啥?在 ThreadLcoal 生命周期里面,都有對(duì) key 值為 null 時(shí)進(jìn)行回收的處理操作?有證據(jù)么?

 

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2021-02-18 16:53:44

內(nèi)存ThreadLocal線程

2020-09-11 07:38:50

內(nèi)存泄漏檢測(cè)

2020-11-09 06:00:04

Windows 10Windows操作系統(tǒng)

2021-08-10 09:58:59

ThreadLocal內(nèi)存泄漏

2018-10-25 15:24:10

ThreadLocal內(nèi)存泄漏Java

2022-05-09 14:09:23

多線程線程安全

2025-04-01 05:22:00

JavaThread變量

2024-03-22 13:31:00

線程策略線程池

2024-09-29 08:57:25

2022-11-04 08:47:52

底層算法數(shù)據(jù)

2024-02-02 09:00:14

內(nèi)存泄漏對(duì)象

2018-05-08 15:42:30

PC升級(jí)筆記本

2024-03-11 08:22:40

Java內(nèi)存泄漏

2023-12-18 10:45:23

內(nèi)存泄漏計(jì)算機(jī)服務(wù)器

2012-02-22 21:28:58

內(nèi)存泄漏

2025-03-28 08:53:51

2022-08-26 07:33:49

內(nèi)存JVMEntry

2015-03-30 11:18:50

內(nèi)存管理Android

2017-10-22 15:34:34

手機(jī)內(nèi)存清理內(nèi)存手機(jī)

2020-06-08 09:18:59

JavaScript開發(fā)技術(shù)
點(diǎn)贊
收藏

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