https://mp.weixin.qq.com/s/S0IwbXadRgZ86fFLSFObVQ html
天天早上七點三十,準時推送乾貨若是說 ThreadLocal 的話,那確定就會涉及到內存泄漏,爲啥嘞安全
由於 吧啦吧啦 ~多線程
它是爲了解決對象不能被多線程共享訪問的問題,經過 threadLocal.set() 方法將對象實例保存在每一個線程本身所擁有的 threadLocalMap 中,這樣的話每一個線程都使用本身的對象實例,彼此不會影響從而達到了隔離的做用,這樣就解決了對象在被共享訪問時帶來的線程安全問題app
啥意思呢?打個比方,如今公司全部人都要填寫一個表格,可是隻有一支筆,這個時候就只能上我的用完了以後,下我的纔可使用,爲了保證"筆"這個資源的可用性,只須要保證在接下來每一個人的獲取順序就能夠了,這就是 lock 的做用,當這支筆被別人用的時候,我就加 lock ,你來了那就進入隊列排隊等待獲取資源(非公平方式那就另外說了),這支筆用完以後就釋放 lock ,而後按照順序給下我的使用ide
可是徹底能夠一我的一支筆對不對,這樣的話,你填寫你的表格,我填寫個人表格,咱倆誰都不耽擱誰。這就是 ThreadLocal 在作的事情,由於每一個 Thread 都有一個副本,就不存在資源競爭,因此也就不須要加鎖,這不就是拿空間去換了時間嘛源碼分析
在開始以前,我們先把 Thread, ThreadLocal, ThreadLocalMap 的關係捋一捋:ui
在這裏先給個解釋,後面我們再詳細分析:this
首先是由於 ThreadLocal 是基於 ThreadLocalMap 實現的,其中 ThreadLocalMap 的 Entry 繼承了 WeakReference ,而 Entry 對象中的 key 使用了 WeakReference 封裝,也就是說, Entry 中的 key 是一個弱引用類型,對於弱引用來講,它只能存活到下次 GC 以前url
若是此時一個線程調用了 ThreadLocalMap 的 set 設置變量,當前的 ThreadLocalMap 就會新增一條記錄,但因爲發生了一次垃圾回收,這樣就會形成一個結果: key 值被回收掉了,可是 value 值還在內存中,並且若是線程一直存在的話,那麼它的 value 值就會一直存在spa
這樣被垃圾回收掉的 key 就會一直存在一條引用鏈: Thread -> ThreadLocalMap -> Entry -> Value :
就是由於這條引用鏈的存在,就會致使若是 Thread 還在運行,那麼 Entry 不會被回收,進而 value 也不會被回收掉,可是 Entry 裏面的 key 值已經被回收掉了
這只是一個線程,若是再來一個線程,又來一個線程…多了以後就會形成內存泄漏
知道是怎麼形成內存泄漏以後,接下來要作的事情就好說了,不是由於 value 值沒有被回收掉因此纔會致使內存泄露的嘛
那使用完 key 值以後,將 value 值經過 remove 方法 remove 掉,這樣的話內存中就不會有 value 值了,也就防止了內存泄漏嘛
OK ,上面的內容講完了,接下來一一來看
首先,你怎麼知道 ThreadLocal 是基於 ThreadLocalMap 實現的呢?
從源碼知道的~
在源碼中可以看到下面這幾行代碼:
public class ThreadLocal<T> {
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
}
代碼中說的很清楚了,在 ThreadLocal 內部維護着 ThreadLocalMap ,而它的 Entry 則繼承自 WeakReference 的 ThreadLocal<?> ,其中 Entry 的 k 爲 ThreadLocal , v 爲 Object ,在調用 super(k) 時就將 ThreadLocal 實例包裝成了一個 WeakReference
強弱引用這塊內容阿粉就直接放一個表格吧:
引用類型 | 功能特色 |
---|---|
強引用 ( Strong Reference ) | 被強引用關聯的對象永遠不會被垃圾回收器回收掉 |
軟引用( Soft Reference ) | 軟引用關聯的對象,只有當系統將要發生內存溢出時,纔會去回收軟引用引用的對象 |
弱引用 ( Weak Reference ) | 只被弱引用關聯的對象,只要發生垃圾收集事件,就會被回收 |
虛引用 ( Phantom Reference ) | 被虛引用關聯的對象的惟一做用是能在這個對象被回收器回收時收到一個系統通知 |
從表格中應該可以看出來,弱引用的對象只要發生垃圾收集事件,就會被回收
因此弱引用的存活時間也就是下次 GC 以前了
在這裏阿粉就有個問題想問問了:爲何 ThreadLocal 採用弱引用,而不是強引用嘞?
在 ThreadLocalMap 上面有些註釋,我在這裏摘錄一部分,或許能夠從中窺探一二:
To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys
翻譯一下就是:(雖然我英語不是很好
爲了解決很是大且長期使用的問題,哈希表使用了弱引用的 key
假設,假設, ThreadLocal 使用的是強引用,會怎樣呢?
若是是強引用的話,在表格中也可以看出來,被強引用關聯的對象,永遠都不會被垃圾回收器回收掉
若是引用的 ThreadLocal 對象被回收了,可是 ThreadLocalMap 還持有對 ThreadLocal 的強引用,若是沒有 remove 的話, 在 GC 時進行可達性分析, ThreadLocal 依然可達,這樣就不會對 ThreadLocal 進行回收,可是咱們指望的是引用的 ThreadLocal 對象被回收,這樣不就達不到目的了嘛
使用弱引用的話,雖然會出現內存泄漏的問題,可是在 ThreadLocal 生命週期裏面,都有對 key 值爲 null 時進行回收的處理操做
因此,使用弱引用的話,能夠在 ThreadLocal 生命週期中儘量保證不出現內存泄漏的問題
啥?在 ThreadLcoal 生命週期裏面,都有對 key 值爲 null 時進行回收的處理操做?有證據麼?
那必須得有證據,畢竟阿粉但是個負責任的博主,不過阿粉考慮到這篇文章內容已是比較多的了,因此下篇文章阿粉再帶你進行源碼分析好很差
乖~
< END >