ThreadLocalMap是个table数组, 每个table存储<key, value>(ThreadLocal<>, value).每个线程都有一个ThreadLocalMap, 同一个ThreadLocal对象会在每个线程都有数据, 每个线程会存储多个ThreadLocal对象.
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
//2的幂
private static final int INITIAL_CAPACITY = 16;
// table数组存储数据, hash得到数组下标
private Entry[] table;
// hash冲突,往后偏移1个位置存储数据
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
private static int prevIndex(int i, int len) {
return ((i - 1 >= 0) ? i - 1 : len - 1);
}
// 2/3扩容
private void setThreshold(int len) {
threshold = len * 2 / 3;
}
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);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
// 原来数组中已经存在该key键值对, 更新value值
if (k == key) {
e.value = value;
return;
}
// 如果key为null, 从该位置开始清理key为null的数据, 并重新hash存储后面的数据
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
// 数组中没有找到, 新建Entry
tab[i] = new Entry(key, value);
int sz = ++size;
// 清理一些槽位null数据, 数据数量达到阀值, 重hash扩容
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
private Entry getEntry(ThreadLocal<?> key) {
// hashcode mod 数组长度得到下标
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
// 获取匹配key数据成功,返回数据
if (e != null && e.get() == key)
return e;
else
// 命中失败,往后面nextIndex查找
return getEntryAfterMiss(key, i, e);
}
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
while (e != null) {
ThreadLocal<?> k = e.get();
// 往后查找数据匹配,返回
if (k == key)
return e;
// 往后查找发现key null的数据, 存在破坏失效数据,需要清除并且重新hash后面的数据
if (k == null)
expungeStaleEntry(i);
else
// 移动指针往后查找
i = nextIndex(i, len);
e = tab[i];
}
return null;
}
// index i开始存在破坏失效数据,需要清除并且重新hash后面的数据
private int expungeStaleEntry(int staleSlot) {
Entry[] tab = table;
int len = tab.length;
// expunge entry at staleSlot
// 将index staleSlot数据置null
tab[staleSlot].value = null;
tab[staleSlot] = null;
// size - 1
size--;
// Rehash until we encounter null
Entry e;
int i;
// 从staleSlot开始往后index,遍历数据key是否为null
for (i = nextIndex(staleSlot, len);
(e = tab[i]) != null;
i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
// key值为null, 需要置null回收
if (k == null) {
e.value = null;
tab[i] = null;
size--;
} else {
// key值不为null, 数据有效, 重新计算索引值
int h = k.threadLocalHashCode & (len - 1);
// 新值不是原来的了
if (h != i) {
// 将原来坑位置null
tab[i] = null;
// Unlike Knuth 6.4 Algorithm R, we must scan until
// null because multiple entries could have been stale.
// 若hash冲突, 该位置已经存储别的数据
while (tab[h] != null)
// 往后查找合适位置
h = nextIndex(h, len);
// 得到合适位置, 存放数据
tab[h] = e;
}
}
}
return i;
}
// 达到阀值, 扩容2倍, 所有数据重新计算索引
private void resize() {
Entry[] oldTab = table;
int oldLen = oldTab.length;
int newLen = oldLen * 2;
Entry[] newTab = new Entry[newLen];
int count = 0;
for (int j = 0; j < oldLen; ++j) {
Entry e = oldTab[j];
if (e != null) {
ThreadLocal<?> k = e.get();
if (k == null) {
e.value = null; // Help the GC
} else {
int h = k.threadLocalHashCode & (newLen - 1);
while (newTab[h] != null)
h = nextIndex(h, newLen);
newTab[h] = e;
count++;
}
}
}
setThreshold(newLen);
size = count;
table = newTab;
}