原文發(fā)表于:http://blog.csdn.net/qq_27485935 , 大家沒事可以去逛逛 (? ??_??)?
ThreadLocal
概述: 位于 java.lang 包下, 是一個線程內(nèi)部的數(shù)據(jù)存儲類, 通過它可以在指定線程中存儲數(shù)據(jù), 數(shù)據(jù)存儲之后, 只有在指定線程中才可以獲取到存儲的數(shù)據(jù)。
使用場景: Looper、 ActivityThread
基本用法:
mThreadLocal = new ThreadLocal<Integer>();
mThreadLocal.set(10); // 通過 set 方法設(shè)值
mThreadLocal.get(); // 通過 get 方法取值
源碼解析
ThreadLocal#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);
}
① ThreadLocal#getMap
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
我們一步步分析, 首先通過 getMap() 方法獲取 Thread 內(nèi)部 的 threadLocals 對象。 而 ThreadLocalMap 為 ThreadLocal 內(nèi)部的靜態(tài)類。
ThreadLocalMap
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;
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) {
e.value = value;
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();
}
}
源碼可見, ThreadLocalMap 通過 Entry 數(shù)組來保存鍵值對的, 并且對鍵也是弱引用狀態(tài)。 set 一個數(shù)值, 將會取出鍵(ThreadLocal) 中的 threadLocalHashCode 值, 而 threadLocalHashCode 是唯一的, 所以可以通過它來確定數(shù)值在 Entry 數(shù)組中的位置。
所以回到剛剛的 ThreadLocal#set 方法。 先從 Thread 類中取出維持線程本地數(shù)據(jù)的 ThreadLocalMap 類, 若 map 對象不為空, 直接將 ThreadLocal 和數(shù)據(jù)作為參數(shù) set 到 map 中維持的 table 數(shù)組中。 若 map 對象為空, 調(diào)用 createMap 方法, 創(chuàng)建 ThreadLocalMap 對象, 設(shè)入數(shù)據(jù)并將該對象設(shè)置到 Thread 對象當中。 以下為 createMap 源碼。
ThreadLocal#createMap
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
接下來分析 get 方法
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();
}
同樣, 獲取當前線程對象, 并獲取維持線程本地數(shù)據(jù)的 threadLocals, 以 ThreadLocal 對象取出對應(yīng)數(shù)值對象。 如果對象不為空, 就強制轉(zhuǎn)化為泛型 T 對應(yīng)的類型。 若 map 為空, 或者鍵值對取出數(shù)據(jù)對象為空, 就調(diào)用 setInitialValue 方法, 以下代碼就不解釋了。
ThreadLocal#setInitialValue
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
protected T initialValue() {
return null;
}
從 ThreadLocal 的 set 和 get 方法可以看出, 它們所操作的對象都是當前線程的 threadLocals 對象中的 table 數(shù)組, 因此在不同線程中訪問同一個 ThreadLocal 的 set 和 get 方法, 他們對 ThreadLocal 所做的讀/寫操作僅限于各個線程的內(nèi)部, 獲取的值也就不同了。