ThreadLocal使用場景有哪些?

image.png
推薦學習:必刷的30萬面試題:巧用弱引用解決ThreadLocal記憶體洩漏!
Thread類中有兩個變量threadLocals和inheritableThreadLocals,二者都是ThreadLocal内部類ThreadLocalMap類型的變量,我們通過檢視内部内ThreadLocalMap可以發現實際上它類似于一個HashMap。在預設情況下,每個線程中的這兩個變量都為null:
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
隻有當線程第一次調用ThreadLocal的set或者get方法的時候才會建立他們。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
除此之外,每個線程的本地變量不是存放在ThreadLocal執行個體中,而是放在調用線程的ThreadLocals變量裡面。也就是說,ThreadLocal類型的本地變量是存放在具體的線程空間上,其本身相當于一個裝載本地變量的載體,通過set方法将value添加到調用線程的threadLocals中,當調用線程調用get方法時候能夠從它的threadLocals中取出變量。如果調用線程一直不終止,那麼這個本地變量将會一直存放在他的threadLocals中,是以不使用本地變量的時候需要調用remove方法将threadLocals中删除不用的本地變量,防止出現記憶體洩漏。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
ThreadLocal記憶體洩露問題如何避免?
每個Thread都有一個ThreadLocal.ThreadLocalMap的map,該map的key為ThreadLocal執行個體,它為一個弱引用,我們知道弱引用有利于GC回收。當ThreadLocal的key == null時,GC就會回收這部分空間,但是value卻不一定能夠被回收,因為他還與Current Thread存在一個強引用關系,如下
- ThreadLocal 不是用于解決共享變量的問題的,也不是為了協調線程同步而存在,而是為了友善每個線程處理自己的狀态而引入的一個機制。這點至關重要。
- 每個Thread内部都有一個ThreadLocal.ThreadLocalMap類型的成員變量,該成員變量用來存儲實際的ThreadLocal變量副本。
- ThreadLocal并不是為線程儲存對象的副本,它僅僅隻起到一個索引的作用。它主要是為每一個線程隔離一個類的執行個體,這個執行個體的作用範圍僅限于線程内部。