ThreadLocal 是為多線程服務(wù)的业筏。本質(zhì)上ThreadLocal是一個關(guān)于創(chuàng)建線程局部變量的類纤怒。
通常情況下,我們創(chuàng)建的變量是可以被任何一個線程訪問并修改的截歉。而使用ThreadLocal創(chuàng)建的變量只能被當(dāng)前線程訪問而咆,其他線程則無法訪問和修改霍比。舉個例子, 服務(wù)器同時被100個用戶訪問暴备,訪問的時候需要對用戶信息進行操作悠瞬,這里threadLocal就可以用來對這100個用戶信息進行thread級別的隔離。
ThreadLocal是如何做到變量只能被當(dāng)前線程訪問呢?
首先需要聲明的是thread local是通過給thread創(chuàng)建變量副本的方式來存儲變量的浅妆。這些需要被線程使用到的變量就是存儲在thread對象的threadLocals屬性上望迎。
這里又要提到ThreadLocalMap,這個是threadlocals的類型凌外。從這個角度來看ThreadLocal類更像是一個util類辩尊,主要的職責(zé)就是幫助thread管理threadLocals屬性。
變量存儲
利用threadlocal對象 set 變量到thread上時調(diào)用的set方法源碼是通過獲取當(dāng)前thread上綁定的threadlocals屬性的值來進行操作康辑,最終所有的值真正存儲的位置其實都在thread本身與threadlocal對象并無直接關(guān)系摄欲。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
再來看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();
}
這里的設(shè)計就有點意思了,首先先從thread上拿到了threadlocals屬性疮薇,這是一個ThreadLocalMap類型的值胸墙,也是數(shù)據(jù)真實的存儲位置。thread所關(guān)聯(lián)的所有threadlocal其實都存在這個map的entry里按咒,也就是說不管這個thread里持有了多少個threadlocal實例迟隅,變量副本存儲的地方有且只有一個map的entry。
每個Thread 維護一個 ThreadLocalMap 映射表励七,這個映射表的 key 是 ThreadLocal 實例本身智袭,value 是真正需要存儲的 Object。
也就是說 ThreadLocal 本身并不存儲值掠抬,它只是作為一個 key 來讓線程從 ThreadLocalMap 獲取 value吼野。值得注意的是圖中的虛線,表示 ThreadLocalMap 是使用 ThreadLocal 的弱引用作為 Key 的剿另,弱引用的對象在 GC 時會被回收箫锤。
threadlocal的存在是為了幫助thread進行threadlocals屬性的關(guān)于制定key(threadllocal其實就是threadlocalMap的key)的賦值和取值。多線程之間的threadlocal實例本身其實是共享的,所以使用的時候一般定義成static變量雨女,達到thread間共享實例的目的。