遇到ConcurrentHashMap
的奇怪行为:首先,使用putIfAbsent()
和remove()
之类的比较和设置操作,几个线程会同时修改地图。经过一段时间(几十秒甚至一分钟)后,另一个线程使用两种方法检查地图是否为空:
myMap.isEmpty()
方法myMap.entrySet().iterator().hasNext()
令人惊讶的是,这两种方法给出了不同的结果。在此之后,isEmpty()
会返回true
,iterator.hasNext()
会返回true
。执行调用时不会有任何暂停,此时不会在地图上执行写操作。
请注意,根据日志,当isEmpty()
返回false
而iterator.hasNext()
同时返回false
时,不存在任何情况。因此,始终isEmpty()
方法不会“看到”地图中的任何条目。
不知道这是ConcurrentHashMap
的预期行为。
文档说明:
请记住,聚合状态方法的结果(包括size,isEmpty和containsValue)通常仅在映射未在其他线程中进行并发更新时才有用。否则,这些方法的结果反映了可能足以用于监视或估计目的的瞬态,但不适用于程序控制。
这表明,当没有正在进行的写操作时,size()
和isEmpty()
等方法应返回与地图的实际内容一致的值。
答案 0 :(得分:1)
ConcurrentHashMap.getEntrySet()
的javadoc告诉您从集合中获取的迭代器弱一致。
java.util.concurrent
包的Javadoc解释了什么"弱一致"的意思是:
...他们的迭代器和Spliterators提供弱一致而不是快速失败的遍历:
- 他们可以与其他行动同时进行
- 他们永远不会抛出ConcurrentModificationException
- 他们可以保证在施工时只存在一次元素,并且可能(但不保证)反映施工后的任何修改。
最后一颗子弹是重要的。它告诉您迭代器是创建迭代器时映射中的内容的视图。如果您随后更改了地图的内容,迭代器的内容将不会发生变化。