ThreadLocal提供了一個線程獨立的變量闽铐。在不同線程中調(diào)set,get設(shè)置的值都是和該線程相關(guān)的蝶怔。網(wǎng)上對ThreadLocal的實現(xiàn)眾說紛紜,今天來看下源碼兄墅√咝牵基于JDK1.8。
支持原創(chuàng)隙咸,轉(zhuǎn)載請注明出處沐悦。
類圖
ThreadLocal.png
ThreadLocal.set方法
public void set(T value) {
Thread t = Thread.currentThread(); //獲取當(dāng)前線程對象
ThreadLocalMap map = getMap(t); //獲取ThreadLocalMap對象
if (map != null)
map.set(this, value); //調(diào)用ThreadLocalMap的set方法
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals; //返回Thread的ThreadLocalMap成員變量
}
ThreadLocal.ThreadLocalMap threadLocals = null; //Thread的ThreadLocalMap成員
該方法獲取當(dāng)前線程的Thread對象中的trheadLocal成員變量,調(diào)用它的set方法五督。
ThreadLocalMap.set方法
private void set(ThreadLocal<?> key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1); //通過hash值藏否,計算下標(biāo)
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) { //不斷獲取下一個下標(biāo)直到某個槽沒有元素
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();
}
我們看下Entry這個類:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
這個類繼承自WeakReference,所以只要ThreadLocal對象存在充包,那么設(shè)置在里面的值就不會被回收副签。我們看下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) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
和set方法類似基矮。我們看下map.getEntry方法:
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1); //計算下標(biāo)
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
和set方法類似淆储,一看就明白了。
總結(jié)
我們最后回顧下類圖:
ThreadLocal.png
支持原創(chuàng)家浇,轉(zhuǎn)載請注明出處本砰。
github:https://github.com/gatsbydhn