ConcurrentWeakKeyHashMap isEmpty 方法
以下是 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
此方法是 Java 中相同 ConcurrentHashMap 的副本。
这种
Map
使用每个段的modCount
来跟踪操作期间它是否在不同的步数中保持不变。在我们遍历 Map 的过程中,实际上可能还有其他操作修改 Map。这称为 ABA 问题。我们询问地图是否为空,事实上它不是,但偶然它看起来是空的。一个简单的例子:此时我们决定询问地图并查看段 1,该段似乎是空的。
现在出现另一个算法,将一个元素插入段 1,但从段 3 中删除另一个元素。Map 从来不为空。
我们的线程现在再次运行,我们查看段 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 发生了一些变化,那么它首先就不是空的。也就是说,第二个循环正在做什么。
希望这有帮助。
编辑
如果段包含某些内容或者自第一个循环以来某些内容被修改,则该评估结果为 true。如果该段不包含任何内容并且自第一个循环以来没有任何更改,则其计算结果为 false(这意味着:段为空)。或者,换句话说:我们可以确定自从第一次查看检查的段以来它一直是空的。
This method is a copy of the same in Javas ConcurrentHashMap.
This kind of
Map
is using amodCount
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:In this moment we decide to ask the Map and look into segment 1, which appears to be empty.
Now another algorithm comes and inserts an element to segment 1, but removes the other from segment 3. The Map was never empty.
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 meansmcsum>=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 themodCount
of segment 1 now it is 1 and thecount
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
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.
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 allmcsum
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()
andisEmpty()
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.