Java ThreadLocal原始碼解析: Thread和ThreadLocal
阿新 • • 發佈:2018-11-21
之前對TreadLocal有所理解,對原理也有所瞭解,但一直不深入,重新整理,希望藉以加深理解和印象。
在Jdk1.8中,ThreadLocal相關程式碼主要分為三部分:
- Thread,其中Thread中儲存對ThreadLocal.ThreadLocalMap的引用,作為Thread類的default屬性;
- ThreadLocal,類似於執行緒中的T和readLocal.ThreadLocalMap的管理類,提供獲取、設定、刪除等管理方法;
- ThreadLocal.ThreadLocalMap.ThreadLocal,是ThreadLocal的靜態內部內,底層陣列結構的維護類,包含擴容、獲取等功能,是ThreadLocal的底層核心實現。
1. Thread類
/* 本現場的ThreadLocal. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* 繼承自父類來的ThreadLocal.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
通過Thread的建構函式可知預設情況下,inheritableThreadLocals會通過父類的threadLocal初始化,除非特別指明不繼承父類的threadLocal。
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { …… …… // 如果指明要繼承,並且父執行緒的threadLocal不為空 if (inheritThreadLocals && parent.inheritableThreadLocals != null) // 通過ThreadLocal建立inheritableThreadLocals this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize; …… …… }
小結:每個執行緒中都有兩個屬性,即兩個ThreadLocalMap,其中一個為執行緒自己的,一個是初始化執行緒時,從父執行緒中的拿來建立的,預設如果父執行緒有threadLocal,子執行緒會繼承父執行緒的threadLocal.
2. ThreadLocal類
前文中所說的,ThreadLocal類類似於ThreadLocalMap管理端。ThreadLocal中主要屬性和方法如下圖:
以下是ThreadLocal中核心方法分析:
// 使用線性探測法進行map的擴容 private final int threadLocalHashCode = nextHashCode(); /** * 靜態全域性的儲存下一個hash碼 */ private static AtomicInteger nextHashCode = new AtomicInteger(); /** * hashCode增量 */ private static final int HASH_INCREMENT = 0x61c88647; // 下一個hashCode增加增量 private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); } /* 重要邏輯,當執行緒1呼叫ThreadLocal的get()方法時,首先拿到執行緒1的threadLocals屬性, * 如果不為空, 通過以當前ThreadLocal為key值獲取ThreadLocal中存放的值。這裡有點繞, * 實際相當於,在執行ThreadLocal<String> threadLocal = new ThreadLocal<String>();後,通 * 過get()方法,將拿到執行緒1中threadLocals通過get()方法以threadLocal為key值的設定的值。 * / public T get() { Thread t = Thread.currentThread(); //獲取當前執行緒 ThreadLocalMap map = getMap(t); //獲取當前執行緒的ThreadLocalMap, 即那個屬性 if (map != null) { // 如果當前執行緒存在ThreadLocal ThreadLocalMap.Entry e = map.getEntry(this); // ThreadLocalMap中以ThreadLocal為key,獲取ThreadLocalMap中存放的值 if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; // 轉化為正確格式,泛型 return result; } } return setInitialValue(); } /* * setInitialValue和set(T value)內部邏輯類似,只是一個傳了初始值,一個沒有,如果沒傳初始值,則為null */ private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); // 獲取當前執行緒 ThreadLocalMap map = getMap(t); // 拿到當前執行緒的threadLocals, if (map != null) map.set(this, value); // 在threadLocalMap中設定key為當前ThreadLocal, value為value的值 else createMap(t, value); // 建立一個ThreadLocalMap,並把引用賦值給當前執行緒的threadLocals return value; } public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); //為當前執行緒建立一個threadMap } static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) { //這是個靜態方法,在Thread中呼叫,即如果要繼承父類的threadLocal,將通過這個房間建立 return new ThreadLocalMap(parentMap); }
總結:重要的是ThreadLocal中的get和set方法,get方法將最終拿到當前執行緒的threadLocals,這是一個map,在set的時候以ThreadLocal為key值,實際上是以ThreadLocal的threadLocalHashCode為key值。