设为首页 加入收藏

TOP

深入理解 ThreadLocal(四)
2019-09-14 00:53:03 】 浏览:157
Tags:深入 理解 ThreadLocal
// 当前 key 的哈希,即在数组 table 中的位置 for (Entry e = tab[i]; e != null; // 循环直到碰到空 Entry e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); if (k == key) { // 更新 key 对应的值 e.value = value; return; } if (k == null) { // 替代过期 entry replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }
  1. 通过 key.threadLocalHashCode & (len-1) 计算出初始的哈希值
  2. 不断调用 nextIndex() 直到找到空 Entry
  3. 在第二步遍历过程中的每个元素,要处理两种情况:

    (1). k == key,说明当前 key 已存在,直接更新值即可,直接返回

    (2). k == null, 注意这里的前置条件是 entry != null。说明遇到过期 Entry,直接替换
  4. 不属于 3 中的两种情况,则将参数中的键值对插入空 Entry 处
  5. cleanSomeSlots()/rehash()

先来看看第三步中的第二种特殊情况。Entry 不为空,但其中的 key 为空,什么时候会发生这种情况呢?对,就是前面说到内存泄漏时提到的 过期 Entry。我们都知道 Entry 的 key 是弱引用的 ThreadLocal,当外部没有它的任何强引用时,下次 GC 时就会将其回收。所以这时候的 Entry 理论上也是无效的了。

由于这里是在 set() 方法插入元素的过程中发现了过期 Entry,所以只要将要插入的 Entry 直接替换这个 key==null 的 Entry 就可以了,这就是 replaceStaleEntry() 的核心逻辑。

replaceStaleEntry()

private void replaceStaleEntry(ThreadLocal<?> key, Object value, int staleSlot) {
    Entry[] tab = table;
    int len = tab.length;
    Entry e;

    // Back up to check for prior stale entry in current run.
    // We clean out whole runs at a time to avoid continual
    // incremental rehashing due to garbage collector freeing
    // up refs in bunches (i.e., whenever the collector runs).
    // 向前找到第一个过期条目
    int slotToExpunge = staleSlot;
    for (int i = prevIndex(staleSlot, len);
        (e = tab[i]) != null;
        i = prevIndex(i, len))
        if (e.get() == null)
            slotToExpunge = i; // 记录前一个过期条目的位置

    // Find either the key or trailing null slot of run, whichever occurs first
    // 向后查找,直到找到 key 或者 空 Entry
    for (int i = nextIndex(staleSlot, len);
        (e = tab[i]) != null;
        i = nextIndex(i, len)) {
        ThreadLocal<?> k = e.get();

        // If we find key, then we need to swap it
        // with the stale entry to maintain hash table order.
        // The newly stale slot, or any other stale slot
        // encountered above it, can then be sent to expungeStaleEntry
        // to remove or rehash all of the other entries in run.
        if (k == key) {

            // 如果在向后查找过程中发现 key 相同的 entry 就覆盖并且和过期 entry 进行交换
            e.value = value;

            tab[i] = tab[staleSlot];
            tab[staleSlot] = e;

            // Start expunge at preceding stale entry if it exists
            // 如果在查找过程中还未发现过期 entry,那么就以当前位置作为 cleanSomeSlots 的起点
            if (slotToExpunge == staleSlot)
                slotToExpunge = i;
            cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
            return;
        }

        // If we didn't find stale entry on backward scan, the
        // first stale entry seen while scanning for key is the
        // first still present in the run.
        // 如果向前未搜索到过期 entry,而在向后查找过程遇到过期 entry 的话,后面就以此时这个位置
        // 作为起点执行 cleanSomeSlots
        if (k == null && slotToExpunge == staleSlot)
            slotToExpunge = i;
    }

    // If key not found, put new entry in stale slot
    // 如果在查找过程中没有找到可以覆盖的 entry,则将新的 entry 插入在过期 entry
    tab[staleSlot].value = null;
    tab[staleSlot] = new Entry(key, value);

    // If there are any other stale entries in run, expunge them
    // 在上面的代码运行过程中,找到了其他的过期条目
    if (slotToExpunge != staleSlot)
        cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
}

看起来挺累人的。在我理解,replaceStaleEntry 只是做一个标记的作用,在各种情况下最后都会调用 cleanSomeSlots 来真正的清理过期条目。

你可以看到 ``

cleanSomeSlots()

private boolean cleanSomeSlots(int i, int n) {
    boolean removed = false;
    Entry[] tab = table;
    int len = tab.length;
    do {
        i = nextIndex(i, len);
        Entry e = tab[i];
        if (e != null && e.get() == null) {
            n = len;
            removed = true;
            i = expungeStaleEntry(i); // 需要清理的 Entry
        }
    } while ( (n >>&
首页 上一页 1 2 3 4 5 下一页 尾页 4/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Android设计模式—观察者模式 下一篇Android源码阅读技巧--查找开发者..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目