【原始碼學習】ThreadLocal
大概介紹
ThreadLocal通俗說法:執行緒的本地變數,通過為每個執行緒建立副本的方式解決執行緒隔離問題,實現執行緒中的變數傳遞
比如:
- 一個老專案,要從單執行緒的改為多執行緒實現了,那麼對於一些變數,不是執行緒共享的,就要用ThreadLocal包裝起來
- 每個執行緒對應一個請求連線,在這個執行緒中的多個類、方法都要用到這個請求的使用者資訊,可見這個資訊不是線上程間共享的,那麼用ThreadLocal把使用者資訊包裝起來
ThreadLocalMap
- ThreadLocalMap是ThreadLocal的一個內部靜態類,Thread類裡面有兩個ThreadLocal.ThreadLocalMap型別的內部物件,分別為threadLocals、inheritableThreadLocals。threadLocals是執行緒獨佔的變數,子執行緒可以讀到父執行緒inheritableThreadLocals變數的值。
- ThreadLocalMap維護著一堆key是ThreadLocal型別,value隨便的Entry。也就是說,Thread類的threadLocals物件有一個內部的Entry[]型別的table變數,table的每一個Entry的key是ThreadLocal物件,value隨便。
- ThreadLocal<?>型別的成員是一個弱引用,其特點是,當引用元素無強引用時,JVM GC時會立即回收引用元素。劃重點!!!這裡,知道弱引用怎麼寫了嗎?!!!!
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
// 初始化ThreadLocalMap
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
}
方法
public T get();
public void set(T value);
public void remove();
protected T initialValue();
1. initialValue方法
預設的initialValue是返回null,你也可以在建立ThreadLocal變數的時候重寫該函式。
// 預設的
protected T initialValue() {
return null;
}
// 重寫initialValue函式的實現
private static final ThreadLocal<Map<Charset, CharsetDecoder>> decoders =
new ThreadLocal<Map<Charset, CharsetDecoder>>()
{
@Override
protected Map<Charset, CharsetDecoder> initialValue()
{
return new IdentityHashMap<>();
}
};
2. get方法
首先獲取當前的執行緒,然後獲取當前執行緒的threadLocals,也就是執行緒獨佔變數,通過map.getEntry(this)獲取Entry,這裡的this代表一個ThreadLocal物件,即entry的key,返回這個entry的value。
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
3. set方法
這個同get,不解釋了
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
4. remove方法
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
記憶體洩漏
ThreadLocalMap的key ThreadLocal是弱引用的原因:
- 如果使用強引用,則key永遠都不會被回收,生命週期和執行緒一樣
- 使用強引用,一旦key被回收,則就只剩ThreadLocalMap中的弱引用了,會在下次gc的時候被回收。
- 如果key被回收了,那麼對應的value沒有被回收,為了避免因此造成的記憶體洩漏,每次get()、set()、remove() ThreadLocalMap中的值的時候,會自動清理key為null的value。
- 一個比較好的做法是,在不需要的時候,手動remove掉。
相關文章
- ThreadLocal原始碼thread原始碼
- ThreadLocal原始碼分析thread原始碼
- ThreadLocal 原始碼分析thread原始碼
- ThreadLocal原始碼解析thread原始碼
- ThreadLocal原始碼閱讀thread原始碼
- ThreadLocal原始碼解讀thread原始碼
- Thread、ThreadLocal原始碼解析thread原始碼
- ThreadLocal 原始碼解讀thread原始碼
- ThreadLocal 原始碼淺析thread原始碼
- ThreadLocal部分原始碼分析thread原始碼
- ThreadLocal和ThreadLocalMap原始碼分析thread原始碼
- ThreadLocal底層原始碼解析thread原始碼
- ThreadLocal與ThreadLocalMap原始碼分析thread原始碼
- 原始碼|ThreadLocal的實現原理原始碼thread
- ThreadLocal原始碼解析-Java8thread原始碼Java
- 結合原始碼談談ThreadLocal!原始碼thread
- ThreadLocal應用及原始碼分析thread原始碼
- ThreadLocal原始碼和圖文分析thread原始碼
- 原始碼學習原始碼
- Netty原始碼學習8——從ThreadLocal到FastThreadLocal(如何讓FastThreadLocal記憶體洩漏doge)Netty原始碼threadAST記憶體
- 【Java併發程式設計】面試常考的ThreadLocal,超詳細原始碼學習Java程式設計面試thread原始碼
- 一次ThreadLocal原始碼解析之旅thread原始碼
- fishhook原始碼學習Hook原始碼
- MMKV原始碼學習原始碼
- vue原始碼學習Vue原始碼
- EventBus原始碼學習原始碼
- ObjectMapper原始碼學習ObjectAPP原始碼
- express原始碼學習Express原始碼
- go原始碼學習Go原始碼
- 學習HashMap原始碼HashMap原始碼
- Java容器原始碼學習--ArrayList原始碼分析Java原始碼
- Vue 原始碼學習(一)Vue原始碼
- Okio 框架原始碼學習框架原始碼
- java原始碼學習-SpliteratorJava原始碼
- jQuery原始碼學習之$()jQuery原始碼
- vue observer 原始碼學習VueServer原始碼
- 來聊聊原始碼學習原始碼
- 原始碼學習之EllipsizingTextView原始碼TextView