知名的政府網(wǎng)站建設企業(yè)鏈接點擊量軟件
一、ThreadLocal 引用關系
圖解關系說明:
- 每個線程擁有自己的
ThreadLocalMap
屬性; - ThreadLocalMap 的存儲結構為
Entry[]
數(shù)組; - Entry的Key是ThreadLocal類型且
弱引用
指向ThreadLocal對象,Value是我們自己定義的泛型值對象; - ThreadLocal的生命周期是GC,ThreadLocalMap的生命周期是和Thread同步;
解析:當線程使用Threadlocal 時,是將Threadlocal 當做自己線程屬性ThreadLocalMap中一個Entry的key值,實際上存放的變量是Entry的value值,實際要使用的值是value值。
- value值為什么不存在并發(fā)問題呢,因為它只有一個線程能訪問。
- threadlocal可以當做一個索引,可以有多個threadlocal 變量,不同的threadlocal對應于不同的value值,他們之間互不影響。
- ThreadLocal為每一個線程都提供了變量的副本,使得每個線程在某一時間訪問到的并不是同一個對象,這樣就隔離了多個線程對數(shù)據(jù)的數(shù)據(jù)共享。
強引用:GC不會被清理掉;
軟引用:SoftReference內存不足時會背垃圾回收器回收;
弱引用:WeakReference 當jvm進行垃圾回收就回收;
虛引用:沒有引用
二、ThreadLocal 使用方法解析
// TODO:對應源碼及注釋后期補上
- get——獲取threadlocal局部變量
- set——設置threadlocal局部變量
- initialvalue——設置局部變量的初始值
- remove——刪除該局部變量
三、ThreadLocal 常見面試解答
1. ThreadLocal和普通線程中的變量的區(qū)別?
- 普通變量在多線程環(huán)境下是線程共享的,會有并發(fā)問題;
- ThreadLocal在多線程環(huán)境下為線程私有變量,值對其他線程不可見,不會有多線程訪問不安全的情況。
2. key為什么設置為弱引用?
- 強引用也無能為力:業(yè)務使用完ThreadLocal的時候,ThreadLocalRef被回收了,但是還是存在key的強引用,導致Entry對象還是無法被回收;
- 弱引用的好處:當前線程仍然運行的情況下,就算忘記調用Remove()方法,在下次使用ThreadLocal的時候,會對 key為null的Value進行清除操作,比強引用多了一層保障。
3. 為什么不使用當前線程作為當前的key?
-
直接用當前線程來作為ThreadLocalMap的key,無法區(qū)分放入ThreadLocalMap中的多個value。
比如放入了兩個字符串,無法判斷取出來的是哪一個字符串! -
使用ThreadLocal作為key就不一樣了:每一個ThreadLocal對象都可以由ThreadLocalHashCode屬性唯一區(qū)分或者說每一個ThreadLocal對象都可以由這個對象的名字唯一區(qū)分,所以可以用不同的ThreadLocal作為key,區(qū)分不同的value,方便存取。
4. 如何避免內存泄漏?
- 將ThreadLocal定義為 private static ,使生命周期更長,保證ThreadLocal的強引用一直存在而不會回收,保證在ThreadLocal的弱引用能夠找到Entry的值,并remove掉(ps:這段是其他文章中抄的,我認為應該理解成:下次操作ThreadLocalMap的時候 JDK可以通過remove掉key為null的 Entry。[這個歡迎有大佬指正])
- 每次使用完ThreadLocal的時候都調用remove()方法。
5. ThreadLocal有哪些使用場景?
ThreadLocal使用于以下兩種場景:
- 每個線程需要有自己單獨的實例
- 實例需要在多個方法中共享,但不希望其他線程共享
- JavaWeb中使用ThreadLocal傳遞Session信息;
- 數(shù)據(jù)庫連接,處理數(shù)據(jù)庫事務;
- 日志、調用鏈路追蹤;