ConcurrentWeakKeyHashMap isEmpty 方法

发布于 2024-11-29 04:05:57 字数 2031 浏览 0 评论 0原文

以下是 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;
}

编辑: 用于评估上述 if 块的代码现在位于 ConcurrentWeakKeyHashMapTest

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

The following is isEmpty() method from ConcurrentWeakKeyHashMap.java,
https://github.com/netty/netty/blob/master/src/main/java/org/jboss/netty/util/internal/ConcurrentWeakKeyHashMap.java

Why does it need mcsum, and what does the if(mcsum!= 0) {..} block doing ?

And more importantly, how do I get

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

to evaluate to true?

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;
}

EDIT:
Code to evaluate the above if block is now in ConcurrentWeakKeyHashMapTest

Essentially 1 thread continously monitors the concurrentMap, while another thread continuously add/remove same keypair value

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

菩提树下叶撕阳。 2024-12-06 04:05:57

此方法是 Java 中相同 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 中删除另一个元素。Map 从来不为空。

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

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

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

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

希望这有帮助。

编辑

更重要的是,我如何获得

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

评估为真?

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

This method is a copy of the same in Javas ConcurrentHashMap.

This kind of Map is using a modCount per segment to track during operations if it remained unchanged by different treads. During our traversal of the Map there could actually be other operations modifying the Map. This is called an ABA problem. We are asking the Map if it is empty and in fact it is not, but by accident it appears to be. A simple example:

Map with three segements
Segment 1: size=0
Segment 2: size=0
Segment 3: size=1
  1. In this moment we decide to ask the Map and look into segment 1, which appears to be empty.

  2. Now another algorithm comes and inserts an element to segment 1, but removes the other from segment 3. The Map was never empty.

  3. Our Thread is running now again and we look into segment 2 and 3, both are empty. For us the Map is empty - as a result.

But for any empty slot we tracked whether it was modified, too. And for slot 3 we realize there have been modifications: mc[2]>=1 which means mcsum>=1. This means: since construction the Map was modified at least once. So to answer what mcsum is for: It is a shortcut for the default empty ConcurrentHashMap. If there never have been modifications, we do not need to check for concurrent modifications.

So we know something happened and check again each segment. If now a segment is empty we know what its modCount has been. For segment 3, lets say it was 1, for segment 1 it has been 0. Checking the modCount of segment 1 now it is 1 and the count is > 0 so we know that the Map is not empty.

Still there could be an ABA problem in the second loop as well. But because we know the modCounts we can catch any other concurrent algorithm changing something. So we say if the segment is empty and something changed with the modCount it has not been empty in the first place. That is, what the second loop is doing.

Hope this helps.

EDIT

And more importantly, how do I get

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

to evaluate to true?

This evaluates to true if a segment contains something or if something was modified since the first loop. And it evaluates to false (which means: segment empty) if the segment contains nothing AND nothing was changed since the first loop. Or, to say it differently: We can be sure it has been empty all the time since looked on the checked segment first.

有木有妳兜一样 2024-12-06 04:05:57

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

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

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

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

The mcsum checks if the map has ever been structurally modified. There appears to be no way to reset the modification counts to zero, so if the map has ever contained anything at all mcsum will be non-zero.

The weak keys are only cleaned up when the map is changed through a put, remove, et c, and they are only cleaned up within the modified segment. Retrieving values from the map does not clear up the weak keys. This means the map as implemented will hold many weak keys that have been garbage collected as they are only cleaned up if the same segment is modified.

This means results from the size() and isEmpty() methods will frequently return the wrong result.

With the API as provided your best recourse is to call purgeStaleEntries() prior to checking if the map is empty.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文