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,为防止内存泄露,建议:继承