ThreadLocal
是java中的一個經常使用類,一般用來爲當前線程存儲變量。java
有三種建立方式:數組
ThreadLocal theadLocal = new ThreadLocal<>();
protected T initialValue() {
return null;
}
複製代碼
因此能夠在建立時實現initialValue
,以達到初始化數據的做用:public final static ThreadLocal<Object> theadLocal = new ThreadLocal<Object>(){
@Override
protected Object initialValue() {
return new Object();
}
};
複製代碼
Supplier
在建立時初始化:public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
return new SuppliedThreadLocal<>(supplier);
}
複製代碼
直接用withInitial來建立ThreadLocal:public static final ThreadLocal<Object> current = ThreadLocal.withInitial(() -> {
return new Object();
});
複製代碼
每一個Thread對象中,有一個ThreadLocal.ThreadLocalMap對象:ide
ThreadLocal.ThreadLocalMap threadLocals = null;
複製代碼
ThreadLocal的操做(set/get/remove),就是對當前對象的ThreadLocal.ThreadLocalMap對象的操做:this
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
複製代碼
Entry是ThreadLocalMap內部存儲數據的節點:spa
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
複製代碼
ThreadLocalMap中聲明瞭Entry
數組,做爲數據的存儲:線程
private static final int INITIAL_CAPACITY = 16;
private Entry[] table;
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
// 實例化Entry數組
table = new Entry[INITIAL_CAPACITY];
// 計算數組下標
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
複製代碼
數組的下標,由ThreadLocal.threadLocalHashCode作相關位運算後肯定。code
ThreadLocal.threadLocalHashCode在每一個對象實例化時計算:對象
private final int threadLocalHashCode = nextHashCode();
private static AtomicInteger nextHashCode = new AtomicInteger();
private static final int HASH_INCREMENT = 0x61c88647;
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
複製代碼
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
複製代碼
Reference.clear()
:private void remove(ThreadLocal<?> key) {
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)]) {
if (e.get() == key) {
// 找到key,移除
e.clear();
expungeStaleEntry(i);
return;
}
}
}
複製代碼
remove時,清除的只是key(ThreadLocal對象),並無清除value,爲防止內存泄露,建議:繼承