ThreadLocal是什麼?
ThreadLocalThreadLocal是一個線程內部用於存儲數據的類,通過它可以在指定的線程中存儲數據,數據存儲以後,只有在該線程中可以獲取到存儲的數據,對於其它線程來說無法獲取到數據。個人認爲是一個線程內部的存儲機制。
如何使用?
ThreadLocal<Boolean> threadLocal = new ThreadLocal<>();
這樣就在一個線程創建了ThreadLocal這個對象,這個對象支持範性的,也就是說我們可以存儲的自己想存的任意類型。
threadLocal.set(true);
這樣我們就在當前所在線程,存儲了true。
new Thread("Thread#1") {
@Override
public void run() {
System.out.println(threadLocal.get());
};
}.start();
我們在一個分線程去打印這個剛纔存儲的值會發現是null,因爲這是在兩個線程操作的。如果在當前線程獲取則爲正確剛纔存的值。
如果想移除這個數據也很簡單:
threadLocal.remove();
這就是threadLocal的使用,其實很簡單。 主要記得是區分線程的就ok。
內部源碼是如何實現的呢?
這就是treadLocal中的所有方法了,其實我們最關心的就是set和get方法。
我們先看set:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
這就是set方法,對就這麼幾行。
首先會通過Thread.currentThread();這個方法獲取當前線程的Thread。然後通過getMap()獲取 ThreadLocalMap對象。
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
getMap中也很簡單,就是返回這個線程的threadLocals, 這個ThreadLocal就是 Thread中的一個變量ThreadLocal.ThreadLocalMap threadLocals = null;
其實還是ThreadLocal中的內部類ThreadLocalMap;這裏一會在分析,先順着思路往下走。
獲取map之後會根據判斷如果不是null就進行set,也就是存儲,如果是null就會調用createMap()方法進行創建這個ThreadMap。接下來在看是如何set和createMap的。
創建其實很簡單,直接就是new一個。
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
set方法就稍微複雜了些,因爲這也是核心內容。set方法在內部類ThreadLocalMap中,所以接下來分析下這個ThreadLocalMap類。
ThreadLocalMap
這個類在構造中創建了一個數組, new Entry[INITIAL_CAPACITY]; ,Entry裏面就是一個object的對象,然後裏面主要getEntry和set方法進行存取和讀取。
““
private void set(ThreadLocal key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal k = e.get();
if (k == key) {//這裏判斷這個k和傳進來的key是否相等
e.value = value;//進行存儲後return
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
““
看主要代碼 判斷k和傳進來的key相等話就存儲這個value
get方法:
“`
private Entry getEntry(ThreadLocal
我們再看get:
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();
}
get裏面也是要先獲取當前的Thread這也就是爲什麼ThreadLocal獲取和存儲的都是隻在當前線程的。
然後也是getMap方法獲取這個ThreadLocalMap,這也就是爲什麼裏面就一行代碼,也要寫成一個方來,因爲這是中思路,其他地方獲取直接調用就行,日後擴展的話一樣方便。
再然後就是通過這個map去調用上面說的getEntry方法。
至此,我們就知道ThreadLocal的總體工作流程和思路了。