1. threadlocal簡單介紹
threadlocal:線程私有變量,用于存儲線程隔離的數(shù)據(jù)梁钾,目前我們會用來存儲用戶登錄信息。
2. threadlocal常用函數(shù)
threadlocal常用函數(shù)有四個咆槽,分別是:
- set 存放信息
- get 提取信息
- remove 清空threadlocal的數(shù)據(jù)
- withInitial 初始化get的數(shù)據(jù)陈轿,如果沒初始化圈纺,那么在set之前get到的的值是null
3. ThreadLocalMap介紹
threadlocal存儲數(shù)據(jù)的地方是ThreadLocalMap∏胤蓿現(xiàn)在我們先來看看ThreadLocalMap麦射。
1.ThreadLocalMap類在哪里
2.ThreadLocalMap類的屬性、Entity類灯谣、構造函數(shù)潜秋、getset方法、有趣的replaceStaleEntry和rehash方法
ThreadLocalMap類的屬性
- INITIAL_CAPACITY 數(shù)組長度 & 存儲數(shù)據(jù)的最大值 ;INITIAL_CAPACITY=Entry[]數(shù)組的長度
- Entry[] 數(shù)組胎许,存放ThreadLocal.set的值.結合INITIAL_CAPACITY來看峻呛,一個線程可以創(chuàng)建多個ThreadLocal來存放數(shù)據(jù)。(我以前的就是創(chuàng)建一個ThreadLocal辜窑,但又要存放多個數(shù)據(jù)钩述;結果只能在ThreadLocal存放Map,然后...最終就會浪費資源了穆碎,所以最優(yōu)的解決方案是一個ThreadLocal存放一個值牙勘,一個線程存放多個ThreadLocal)例子如下:
public class CacheUser{
private static ThreadLocal<User> threadLocalUser = new ThreadLocal<User>();
private static ThreadLocal<Group> threadLocalGroup = new ThreadLocal<Group>();
public Group getGroup(){
return threadLocalGroup.get();
}
public User getUser(){
return threadLocalUser.get();
}
}
size 線程創(chuàng)建ThreadLocal的數(shù)量,例如上面代碼所禀,那么size=2方面;size也表示存放的多小個值,跟INITIAL_CAPACITY是有區(qū)別的色徘,size<= INITIAL_CAPACITY
-
threshold 閾值恭金;其實很多地方都會存在閾值這東西,超過閾值就擴容褂策,想ThreadLocal的閾值=INITIAL_CAPACITY的三分之二横腿,這個我們可以通過構造函數(shù)能觀察(擴容的時候會從新刷新threshold的值)
Entry類
Entry可以簡單理解成存放了key和value兩個值的對象
構造函數(shù)
看完上面的可以來看下ThreadLocalMap的構造函數(shù)了。
說明如下:
- 首先初始化數(shù)組長度為16
- firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); 快速計算出Entry存放數(shù)組的下標斤寂,&是位運算符,為什么要INITIAL_CAPACITY - 1呢蔑水?因為數(shù)組坐標從0開始。另外這里只是快速計算出下標扬蕊,因為是第一次存儲搀别,所以就直接使用計算出來的i值做下標,但第二次的時候尾抑,除了要計算這個下標外歇父,還會判斷這個下標是否已經有值了,有值的話就往后移一位再愈,循環(huán)判斷....這就不扯遠了榜苫,后面講set的時候詳細說
- setThreshold 設置閾值,其實很多地方都有閾值這個概念翎冲。超過閾值就擴容而不是等把數(shù)組填滿后擴容
set方法
上源碼:
- 第一步快速計算下標值
- 第二步循環(huán)判斷數(shù)組的坑位是否有值垂睬,有值往后移一位,最后一位的下一位就是0位,再循環(huán)
- 第三步 把Entry放入數(shù)組
- 然后來聊聊截圖兩處地方
- 第一處地方為什么k 會等于null驹饺;這讓我百思不得其解钳枕,百度說因為ThreadLocal是弱引用,會被gc回收赏壹,所以會為空鱼炒。這也是解析了Threadlocal會導致內存溢出的問題,也許因為這個才有remove(當不需要ThreadLocal的時候蝌借,清空ThreadLocal的內容)
- 第二處是擴容
- ThreadLocalMap好幾處地方都存在判斷key是否為空昔瞧,空則清除(防止內存溢出)這樣的操作。
- 其實這里我有個疑問菩佑!為什么要用弱引用自晰,不用強應用來實現(xiàn)呢?
4. inheritableThreadLocals
inheritableThreadLocals實現(xiàn)子線程從父線程繼承值稍坯。使用如下