-- 最近再探Spring,深入研究了一下Spring的Introduce Advice。其中涉及到了关于ThreadLocal的一些内容,回顾了一下,这里做个记录。
-- Java DOC说ThreadLocal存储了一个线程的局部变量,内部究竟是怎样的。具体如下:
-- Thread中维护了一个ThreadLocal.ThreadLocalMap的变量。
ThreadLocal.ThreadLocalMap threadLocals = null;
-- 当我们调用ThreadLocal的set方法的时候,实际上是往Thread.currentThread()也就是当前线程的ThreadLocalMap变量中添加数据。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
-- 由此可见,一个Thread可以维护多个ThreadLocal
-- 再看ThreadLocal.ThreadLocalMap(ThreadLocalMap是ThreadLocal的静态内部类,为了方便,下面简写为ThreadLocalMap)
ThreadLocalMap是不是像他名字所写的那样使用了一个Map来储存一个Thread的局部变量呢?答案是否定的。
private Entry[] table;
实际上它用的是一个ThreadLocalMap.Entry数组。这个数组的初始容量为16.
private static final int INITIAL_CAPACITY = 16;
-- Entry是ThreadLocalMap静态内部类。下面简写为Entry。
-- 那么又是如何往Entry[ ]中添加数据呢?
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();
}
-- 这里使用了ThreadLocal的threadLocalHashCode与16进制的F做与操作的结果作为索引来向Entry数组添加数据。上面判断是否已经使用当前TheadLocal添加了数据,下面对数组越界做处理。具体怎么处理的,时间所限没有深究。
-- 至于Entry本质上就是一个没有存取器的Java Bean。它有两个属性:
ThreadLocal类型的key,
Object类型的Value