- 当执行Threadlocal的set操作后,最后会执行了
cleanSomeSlots
方法,从下表i开始执行清理不新鲜的元素(stale是不新鲜的意思,这里指key为null,value不为null的Entry节点)。 - 如果
cleanSomeSlots
没有清理到元素,即该方法返回false,“且” 当前Threadlocal的Entry数组容量已经超过threadhold
了(threadhold是数组大小的三分之二)。触发rehash()。记住这里还没有扩容呢 - rehash()中再次执行清理不新鲜的元素
expungeStaleEntries();
,这个方法和cleanSomeSlots
不同,cleanSomeSlots
是从某个下标开始清理,expungeStaleEntries();
是从头到尾清理数组中全部不新鲜的元素。 - 清理后判断当前数组容量是否大于
threshold - threshold / 4
即四分之三的threshold
(这里记住是四分之三的threhold就可,也即3/4 * 2/3 * len=1/2 *len即数组大小的二分之一),如果大于threhold的四分之三或者说是二分之一的数组容量大小,则进行扩容。 - 扩容的大小是原来容量的两倍
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();
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();
}
private void rehash() {
expungeStaleEntries();
// Use lower threshold for doubling to avoid hysteresis
if (size >= threshold - threshold / 4)
resize();
}
这里可以看看cleanSomeSlots
和 expungeStaleEntries()
的源码
cleanSomeSlots如下:可以看到是从下标i开始往后进行清理
expungeStaleEntries如下:是从下标0开始清理