大概介紹
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掉,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/171943.html
標籤:其他
上一篇:Java-多執行緒中的鎖
