ThreadLocal的介紹與運用( 五 )

(2 )代碼執行流程
? A. 首先獲取當前線程
? B. 根據當前線程獲取一個Map
? C. 如果獲取的Map不為空,則在Map中以ThreadLocal的引用作為key來在Map中獲取對應的value e , 否則轉到E
? D. 如果e不為null,則返回e.value,否則轉到E
? E. Map為空或者e為空 , 則通過initialValue函數獲取初始值value , 然后用ThreadLocal的引用和value作為firstKey和firstValue創建一個新的Map
總結:先獲取當前線程的 ThreadLocalMap 變量 , 如果存在則返回值 , 不存在則創建并返回初始值 。
4.2 set方法(1 ) 源碼和對應的中文注釋
/*** 設置當前線程對應的ThreadLocal的值** @param value 將要保存在當前線程對應的ThreadLocal的值*/public void set(T value) {// 獲取當前線程對象Thread t = Thread.currentThread();// 獲取此線程對象中維護的ThreadLocalMap對象ThreadLocalMap map = getMap(t);// 如果此map存在if (map != null)// 存在則調用map.set設置此實體entrymap.set(this, value);else// 1)當前線程Thread 不存在ThreadLocalMap對象// 2)則調用createMap進行ThreadLocalMap對象的初始化// 3)并將此實體entry作為第一個值存放至ThreadLocalMap中createMap(t, value);}(2 )代碼執行流程
? A. 首先獲取當前線程,并根據當前線程獲取一個Map
【ThreadLocal的介紹與運用】? B. 如果獲取的Map不為空,則將參數設置到Map中(當前ThreadLocal的引用作為key)
? C. 如果Map為空,則給該線程創建 Map,并設置初始值
4.3 remove方法(1 ) 源碼和對應的中文注釋
/*** 刪除當前線程中保存的ThreadLocal對應的實體entry*/public void remove() {// 獲取當前線程對象中維護的ThreadLocalMap對象ThreadLocalMap m = getMap(Thread.currentThread());// 如果此map存在if (m != null)// 存在則調用map.remove// 以當前ThreadLocal為key刪除對應的實體entrym.remove(this);}(2 )代碼執行流程
? A. 首先獲取當前線程,并根據當前線程獲取一個Map
? B. 如果獲取的Map不為空,則移除當前ThreadLocal對象對應的entry
4.4 initialValue方法/*** 返回當前線程對應的ThreadLocal的初始值* 此方法的第一次調用發生在,當線程通過{@link #get}方法訪問此線程的ThreadLocal值時* 除非線程先調用了 {@link #set}方法 , 在這種情況下,* {@code initialValue} 才不會被這個線程調用 。* 通常情況下,每個線程最多調用一次這個方法 。** <p>這個方法僅僅簡單的返回null {@code null};* 如果程序員想ThreadLocal線程局部變量有一個除null以外的初始值,* 必須通過子類繼承{@code ThreadLocal} 的方式去重寫此方法* 通常, 可以通過匿名內部類的方式實現** @return 當前ThreadLocal的初始值*/protected T initialValue() {return null;}? 此方法的作用是 返回該線程局部變量的初始值 。
(1) 這個方法是一個延遲調用方法,從上面的代碼我們得知,在set方法還未調用而先調用了get方法時才執行,并且僅執行1次 。
(2)這個方法缺省實現直接返回一個null 。
(3)如果想要一個除null之外的初始值 , 可以重寫此方法 。(備注: 該方法是一個protected的方法 , 顯然是為了讓子類覆蓋而設計的)
5. ThreadLocalMap源碼分析5.1 基本結構? ThreadLocalMap是ThreadLocal的內部類,沒有實現Map接口,用獨立的方式實現了Map的功能,其內部的Entry也是獨立實現 。

ThreadLocal的介紹與運用

文章插圖
(1) 成員變量
/*** 初始容量 —— 必須是2的整次冪*/private static final int INITIAL_CAPACITY = 16;/*** 存放數據的table,Entry類的定義在下面分析* 同樣,數組長度必須是2的冥 。*/private Entry[] table;/*** 數組里面entrys的個數,可以用于判斷table當前使用量是否超過負因子 。*/private int size = 0;/*** 進行擴容的閾值,表使用量大于它的時候進行擴容 。*/private int threshold; // Default to 0/*** 閾值設置為長度的2/3*/private void setThreshold(int len) {threshold = len * 2 / 3;}(2) 存儲結構 - Entry
// 在ThreadLocalMap中,也是用Entry來保存K-V結構數據的 。但是Entry中key只能是ThreadLocal對象 , 這點被Entry的構造方法已經限定死了// 另外,Entry繼承WeakReference,使用弱引用,可以將ThreadLocal對象的生命周期和線程生命周期解綁,持有對ThreadLocal的弱引用,可以使得ThreadLocal在沒有其他強引用的時候被回收掉 , 這樣可以避免因為線程得不到銷毀導致ThreadLocal對象無法被回收static class Entry extends WeakReference<ThreadLocal> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal k, Object v) {super(k);value = https://www.huyubaike.com/biancheng/v;}}

推薦閱讀