一.ThreadLocal簡介
ThreadLocal 提供了線程局部變量否纬,提供的局部變量與其他的變量不同狈惫,每個線程都可以通過set與get方法來訪問獨立初始化變量副本。
ThreadLocal 可以理解為線程本地變量暑始,如果定義了一個ThreadLocal對象伴鳖, 每個線程中的ThreadLocal讀寫是線程隔離的,相互不影響锯梁,它提供了一種將可變數(shù)據通過每個線程有自己的獨立副本從而實現(xiàn)線程封閉的機制
包路徑:java.lang.ThreadLocal
二.ThreadLocal相關類
ThreadLocal中嵌套內部類ThreadLocalmap ,這個類本質上就是一個map即碗,與HashMap之類的實現(xiàn)相似,依然是Key-Value的形式陌凳,其中一個內部類Entry ,其中key可以看做是ThreadLocal實例剥懒,但是其本質是持有ThreadLocal的實例弱引用對象
在ThreadLocalMap中并沒有對于ThreadLocalMap的引用,而是ThreadLocalMap在Thread類中合敦,每個線程都向ThreadLocal里面塞值的時候初橘,其實都是向自己持有的ThreadLocalMap里面寫入數(shù)據,讀的時候同理充岛,首先從自己線程中取出自己持有的ThreadLocalMap,然后再根據ThreadLocal引用作為key取出Value保檐,ThreadLocal實現(xiàn)了變量的線程隔離
Thread 源碼部分截圖
UML類圖
ThreadLocal原理圖
首先主線程定義的兩個ThreadLocal變量 ,兩個子線程 線程A和線程B
線程A和線程B 分別持有一個ThreadLocalMap 用于保存自己的副本崔梗,主線程的ThreadLocal中封裝了set和get方法
在線程A和線程B中調用ThreadLocal的Set方法夜只,會首先通過getMap(Thread.currentThread)獲取到線程A或者線程B持有的ThreadLocalMap對象,在調用map.put方法蒜魄,并將ThreadLocal作為key扔亥,將要存儲的數(shù)據作為value 來存放
get和set原理是類似,先獲取當前調用線程的ThreadLocalMap,在從map中獲取value ,并將ThreadLocal作為key
三.ThreadLocalMap源碼分析
在分析ThreadLocalMap 的同時谈为,結合ThreadLocal的方法一起進行分析
private static final int INITIAL_CAPACITY = 16;
private ThreadLocal.ThreadLocalMap.Entry[] table;
private int size;
private int threshold;
private void setThreshold(int var1) {
this.threshold = var1 * 2 / 3;
}
private static int nextIndex(int var0, int var1) {
return var0 + 1 < var1 ? var0 + 1 : 0;
}
private static int prevIndex(int var0, int var1) {
return var0 - 1 >= 0 ? var0 - 1 : var1 - 1;
}
存儲數(shù)據結構 ---Entry 類 繼承WeakReference
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
Entry 繼承WeakReference 使用弱引用旅挤,可以將ThreadLocal對象的生命周期和線程生命周期解綁 ,持有對ThreadLocal的弱引用峦阁,可以使得ThreadLocal在沒有其他強引用的時候被GC回收掉谦铃,這樣可以避免因為線程得不到摧毀 導致ThreadLocal對象無法被垃圾回收器回收