ConcurrentHashMap的迭代器给出了奇怪的结果

时间:2017-01-03 08:15:48

标签: java collections concurrency

ConcurrentHashMap是线程安全的。因此,如果在迭代时添加任何值以进行映射,则不应考虑它们。以下是我的代码:

public class Test {
public static void main(String[] args) {
    ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
    map.put("ONE", 1);
    map.put("TWO", 2);
    Iterator<String> it = map.keySet().iterator();
    while (it.hasNext()) {
        String key = (String) it.next();
        System.out.println(key + " : " + map.get(key));
        map.put("9", 10); // This should not be reflected in the Iterator
        map.put("5", 10); // This should not be reflected in the Iterator
    }
}
}

输出:

    TWO : 2
    ONE : 1
    9 : 10

我的问题是为什么迭代器考虑map.put(“9”,10);

2 个答案:

答案 0 :(得分:3)

  

ConcurrentHashMap是线程安全的。因此,如果在迭代时添加任何值以进行映射,则不应考虑它们。

这是不正确的。这就是javadoc所说的:

  

&#34;同样,Iterators,Spliterators和Enumerations在迭代器/枚举创建时或之后的某个时刻返回反映哈希表状态的元素。&#34 ;

注意&#34;或者&#34;!

它还说迭代器是&#34;弱一致&#34;这意味着:

  

&#34;它们可以保证遍历元素,因为它们在构造时只存在一次,并且可能(但不保证)反映构造后的任何修改。&#34;

简而言之,你期望javadoc显然不会说它们具有迭代器的属性。

答案 1 :(得分:1)

ConcurrentHashMap是线程安全的,但这是一个不同的场景。

使用List,您可以将ListIterator与 ListIterator.Add 一起使用。

使用HashMap,我看到两个解决方案:

  
      
  1. 转换为List,然后返回HashMap

  2.   
  3. 使用其他HashMap   对于新元素,在循环结束后,使用另一个循环添加所有新元素   元素(不太优雅,但有效!)。

  4.   

使用Java 8,您可以考虑使用lambda表达式来简化代码。