当前位置: 首页 > 图灵资讯 > java面试题> 金三银四精选java面试题-ThreadLocalMap扩容机制

金三银四精选java面试题-ThreadLocalMap扩容机制

来源:图灵教育
时间:2024-01-01 19:18:34
 

ThreadLocalMap扩容机制

ThreadLocalMap 的扩容机制和 HashMap 类似,也是在元素数量达到阈值(默认为数组长度的 2/3)时进行扩容。具体来说,在 set() 方法中,如果当前元素数量已经达到了阈值,就会调用 rehash() 方法,rehash()会先去清理过期的Entry,然后还要根据条件判断size >= threshold - threshold / 4 也就是size >= threshold * 3/4来决定是否需要扩容:

private void rehash() {
    //清理过期Entry
    expungeStaleEntries();

    //扩容
    if (size >= threshold - threshold / 4)
        resize();
}

//清理过期Entry
private void expungeStaleEntries() {
    Entry[] tab = table;
    int len = tab.length;
    for (int j = 0; j < len; j++) {
        Entry e = tab[j];
        if (e != null && e.get() == null)
            expungeStaleEntry(j);
    }
}

发现需要扩容时调用resize()方法,resize()方法首先将数组长度翻倍,然后创建一个新的数组newTab。接着遍历旧数组oldTab中的所有元素,散列方法重新计算位置,开放地址解决冲突,然后放到新的newTab,遍历完成之后,oldTab中所有的entry数据都已经放入到newTab中了,然后table引用指向newTab.

需要注意的是,新数组的长度始终是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;
}