ConcurrentHashMap包含值,但size()方法返回0

时间:2016-03-21 10:38:31

标签: java multithreading collections concurrency

遇到ConcurrentHashMap的奇怪行为:首先,使用putIfAbsent()remove()之类的比较和设置操作,几个线程会同时修改地图。经过一段时间(几十秒甚至一分钟)后,另一个线程使用两种方法检查地图是否为空:

  1. 调用myMap.isEmpty()方法
  2. 尝试查看迭代器中是否有任何条目:myMap.entrySet().iterator().hasNext()
  3. 令人惊讶的是,这两种方法给出了不同的结果。在此之后,isEmpty()会返回trueiterator.hasNext()会返回true。执行调用时不会有任何暂停,此时不会在地图上执行写操作。

    请注意,根据日志,当isEmpty()返回falseiterator.hasNext()同时返回false时,不存在任何情况。因此,始终isEmpty()方法不会“看到”地图中的任何条目。

    不知道这是ConcurrentHashMap的预期行为。

    文档说明:

      

    请记住,聚合状态方法的结果(包括size,isEmpty和containsValue)通常仅在映射未在其他线程中进行并发更新时才有用。否则,这些方法的结果反映了可能足以用于监视或估计目的的瞬态,但不适用于程序控制。

    这表明,当没有正在进行的写操作时,size()isEmpty()等方法应返回与地图的实际内容一致的值。

1 个答案:

答案 0 :(得分:1)

ConcurrentHashMap.getEntrySet()的javadoc告诉您从集合中获取的迭代器弱一致

java.util.concurrent包的Javadoc解释了什么"弱一致"的意思是:

  

...他们的迭代器和Spliterators提供弱一致而不是快速失败的遍历:

     
      
  • 他们可以与其他行动同时进行
  •   
  • 他们永远不会抛出ConcurrentModificationException
  •   
  • 他们可以保证在施工时只存在一次元素,并且可能(但不保证)反映施工后的任何修改。
  •   

最后一颗子弹是重要的。它告诉您迭代器是创建迭代器时映射中的内容的视图。如果您随后更改了地图的内容,迭代器的内容将不会发生变化。