源碼分析--ThreadLocal(圖解)
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
想清楚ThreadLocal源碼的原理,那么先搞明白 ThreadLocalMap ,很關(guān)鍵
1.首先我們知道Thread 里面有一個(gè)ThreadLocalMap ;
public class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
}
2.ThreadLocalMap里面有包含了一個(gè)成員變量Entry[] table。
static class ThreadLocalMap {
private Entry[] table;
//Entry繼承了WeakReference<ThreadLocal<?>>, 說明Entry 持有一個(gè)指向ThreadLocal的弱引用。
//弱引用,就是如果一個(gè)對(duì)象只有弱引用指向它,下一次JVM垃圾回收的時(shí)候一定會(huì)被回收調(diào)。
static class Entry extends WeakReference<ThreadLocal<?>> {
//這個(gè)value就是存放我們的數(shù)據(jù)
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
///...省略部分源碼
}
上面的1,2代碼反應(yīng)了如下關(guān)系
一個(gè)Thread里面包含了一個(gè)ThreadLocalMap
一個(gè)ThreadLocalMap包含了一個(gè)table
table是一個(gè)Entry數(shù)組
Entry數(shù)組有一個(gè)value存放數(shù)據(jù),reference弱引用可以指向某個(gè)ThreadLocal

3、ThreadLocalMap包含了一個(gè)Entry[] table, 其實(shí)ThreadLocalMap是底層數(shù)據(jù)結(jié)構(gòu)就是一個(gè)Entry數(shù)組。
ThreadLocalMap是一個(gè)Map,Entry代表一個(gè)哈希槽。
Entry的key(鍵)其實(shí)就是reference, 而value(值)就是上面的value.

ThreadLocalMap存值原理:
1.就是通過Entry的 key的Hash值計(jì)算出Index
2.找到數(shù)組的Index位置,如果該位置為空就存放Entry
3.不為空則Index ++,直到找到一個(gè)空的位置存放 (這里還有一個(gè)擴(kuò)容的問題,暫不討論)
ThreadLocalMap取值原理:
1.就是通過 key的Hash值計(jì)算出Index
2.找到Index的位置Entry,再對(duì)比一下Entry的key和需要查找的key是不是相等,相等則取出value
3.不相等則Index++,然后重復(fù)第2步驟
總結(jié):每個(gè)Thread 對(duì)象里面有一個(gè)ThreadLocalMap。ThreadLocalMap是一個(gè)Map, key是ThreadLocal類型的數(shù)據(jù), value存放數(shù)據(jù)
4.TheadLocal 的set方法
public class ThreadLocal<T> {
public void set(T value) {
//1.獲取當(dāng)前線程的ThreadLocalMap(就是上面說的ThreadLocalMap)
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
// ThreadLocalMap是一個(gè)Map, key是ThreadLocal類型的數(shù)據(jù), value存放數(shù)據(jù)
// 2.map 不為空, Map的key是this對(duì)象本身,value是我們存放的數(shù)據(jù)。
//可能會(huì)疑惑,為什么key存放this?下面再詳細(xì)說明
map.set(this, value);
else
//3.map 為空,為當(dāng)前線程創(chuàng)建一個(gè)Map
createMap(t, value);
}
}
源碼為什么key存放this?
1.一個(gè)Thread有一個(gè)ThreadLocalMap,而ThreadLocalMap可以存放多個(gè)Entry { “key”:ThreadLocal :“value”: object }
2.如下測試代碼所示,當(dāng)我們?cè)诰€程A里面操作threadLocal1.set(1),
其實(shí)就是在線程A自己的ThreadLocalMap的 Entry{ “key”:threadLocal1 :“value”: 1}。
反之, 線程B就是線程B自己的ThreadLocalMap 的 Entry{ “key”:threadLocal1 :“value”: 2}。
public class ThreadLocalTest {
static ThreadLocal<Integer> threadLocal1 = new ThreadLocal<>();
static ThreadLocal<Integer> threadLocal2 = new ThreadLocal<>();
public static void main(String[] args) {
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
try{
threadLocal1.set(1);
threadLocal2.set(2);
}finally {
threadLocal1.remove();
threadLocal2.remove();
}
}
});
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
try{
threadLocal1.set(1);
threadLocal2.set(2);
}finally {
threadLocal1.remove();
threadLocal2.remove();
}
}
});
threadA.start();
threadB.start();
}
}
最后數(shù)據(jù)存放圖如下(table里面entry存放數(shù)據(jù)的位置只是假設(shè),threadLocal1 存放的位置還是通過它的Hash值求出的Index所得 ):

5.ThreadLocal的get方法( 如果看懂上面的set方法,這里就很簡單了)
public T get() {
//1.獲取當(dāng)前線程的ThreadLocalMap(就是上面說的ThreadLocalMap)
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
//map 不為空,根據(jù)this獲取Entry
ThreadLocalMap.Entry e = map.getEntry(this);
//e不為空,返回e.value
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
private T setInitialValue() {
//initialValue() 就是返回了一個(gè)null
T value = initialValue();
Thread t = Thread.currentThread();
//獲取當(dāng)前線程的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
//map 不為空,設(shè)置值為null
map.set(this, value);
else
//map 為空,創(chuàng)建一個(gè)map,并設(shè)置值為null
createMap(t, value);
return value;
}
6.ThreadLocal的數(shù)據(jù)用完后記得使用 threadLocal.remove()移除數(shù)據(jù),不然在某種情況下可能會(huì)導(dǎo)致內(nèi)存泄漏(如圖下描述)

————————————————
版權(quán)聲明:本文為CSDN博主「略。。。。」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:
https://blog.csdn.net/fsdf8sad7/article/details/113939691
鋒哥最新SpringCloud分布式電商秒殺課程發(fā)布
??????
??長按上方微信二維碼 2 秒
感謝點(diǎn)贊支持下哈 
