1

以下是来自 ConcurrentWeakKeyHashMap.java 的 isEmpty() 方法, https://github.com/netty/netty/blob/master/src/main/java/org/jboss/netty/util/internal/ConcurrentWeakKeyHashMap.java

为什么它需要 mcsum,if(mcsum!= 0) {..} 块在做什么?

更重要的是,我如何获得

 if (segments[i].count != 0 || mc[i] != segments[i].modCount) 

评估为真?

public boolean isEmpty() {
    final Segment<K, V>[] segments = this.segments;
    /*
     * We keep track of per-segment modCounts to avoid ABA problems in which
     * an element in one segment was added and in another removed during
     * traversal, in which case the table was never actually empty at any
     * point. Note the similar use of modCounts in the size() and
     * containsValue() methods, which are the only other methods also
     * susceptible to ABA problems.
     */
    int[] mc = new int[segments.length];
    int mcsum = 0;
    for (int i = 0; i < segments.length; ++ i) {
        if (segments[i].count != 0) {
            return false;
        } else {
            mcsum += mc[i] = segments[i].modCount;
        }
    }


    // If mcsum happens to be zero, then we know we got a snapshot before
    // any modifications at all were made.  This is probably common enough
    // to bother tracking.
    if (mcsum != 0) {
        for (int i = 0; i < segments.length; ++ i) {
            if (segments[i].count != 0 || mc[i] != segments[i].modCount) {
                return false;
            }
        }
    }


    return true;
}

编辑: 如果块现在在 ConcurrentWeakKeyHashMapTest中,则评估上述代码

本质上 1 个线程持续监控 concurrentMap,而另一个线程持续添加/删除相同的密钥对值

4

2 回答 2

1

mcsum检查地图是否曾经在结构上进行过修改。似乎没有办法将修改计数重置为零,因此如果地图曾经包含任何内容,那么mcsum它将是非零的。

弱键仅在通过 put、remove 等更改映射时才被清除,并且仅在修改后的段内被清除。从映射中检索值不会清除弱键。这意味着实现的映射将包含许多已被垃圾收集的弱键,因为它们仅在修改同一段时才会被清理。

这意味着size()andisEmpty()方法的结果将经常返回错误的结果。

使用提供的 API,您最好的办法是purgeStaleEntries()在检查地图是否为空之前调用。

于 2011-08-11T08:22:31.457 回答
1

此方法是 Javas ConcurrentHashMap中相同的副本。

这种方法Map是在操作期间使用modCount每个段来跟踪它是否通过不同的胎面保持不变。在我们遍历 Map 的过程中,实际上可能有其他操作修改 Map。这称为ABA 问题。我们正在询问地图是否为空,实际上它不是,但偶然它似乎是。一个简单的例子:

Map with three segements
Segment 1: size=0
Segment 2: size=0
Segment 3: size=1
  1. 在这一刻,我们决定询问地图并查看第 1 段,它似乎是空的。

  2. 现在另一个算法来了,将一个元素插入到段 1,但从段 3 中删除了另一个。地图从来都不是空的。

  3. 我们的线程现在再次运行,我们查看段 2 和 3,两者都是空的。对我们来说,地图是空的——结果。

但是对于任何空槽,我们也跟踪它是否被修改。对于插槽 3,我们意识到已经进行了修改:mc[2]>=1这意味着mcsum>=1. 这意味着:自构建以来,地图至少被修改过一次。所以要回答 mcsum 的用途:它是默认空 ConcurrentHashMap 的快捷方式。如果从未有过修改,我们不需要检查并发修改。

所以我们知道发生了一些事情并再次检查每个部分。如果现在一个段是空的,我们知道它是什么modCount。对于段 3,假设它是 1,对于段 1,它一直是 0。检查modCount段 1 现在它是 1 并且count大于 0,所以我们知道 Map 不是空的。

在第二个循环中仍然可能存在 ABA 问题。但是因为我们知道 modCounts 我们可以捕捉到任何其他并发算法的变化。所以我们说如果这个段是空的,并且随着 modCount 发生了一些变化,它首先不是空的。也就是说,第二个循环在做什么。

希望这可以帮助。

编辑

更重要的是,我如何获得

if (segments[i].count != 0 || mc[i] != segments[i].modCount)

评估为真?

如果段包含某些内容或某些内容自第一次循环以来已被修改,则评估结果为 true。如果段不包含任何内容并且自第一次循环以来没有任何更改,则它的评估结果为 false(这意味着:段为空)。或者,换种说法:我们可以确定自从第一次查看检查段以来它一直是空的。

于 2011-08-11T08:23:42.887 回答