我正在尝试使用 ConcurrentHashMap
的故障保护示例。
下面是我试过的示例片段..
ConcurrentHashMap<String, String> cMap = new ConcurrentHashMap<String, String>();
cMap.put("1", "Windows Phone");
cMap.put("2", "iPhone");
cMap.put("3", "HTC");
Iterator iterator=cMap.keySet().iterator();
while (iterator.hasNext()) {
System.out.println(cMap.get(iterator.next()));
cMap.put("Samsung", "S5");
}
输出是:
Windows Phone
HTC
iPhone
这是我理解的故障安全示例。
但是当我尝试下面的例子时,我得到了不同的输出。
ConcurrentHashMap<String, String> cMap = new ConcurrentHashMap<String, String>();
cMap.put("1", "Windows Phone");
cMap.put("2", "iPhone");
cMap.put("3", "HTC");
Iterator iterator=cMap.keySet().iterator();
while (iterator.hasNext()) {
System.out.println(cMap.get(iterator.next()));
cMap.put("4", "S5");
}
输出是
Windows Phone
HTC
S5
iPhone
以上两个代码片段有什么区别。在第二个代码片段中,我添加了 cMap.put("4", "S5"); 并且它正在被添加。但是在第一个片段中,我添加了 cMap.put("Samsung", "S5");,它没有被添加到 ConcurrentHashmap。我是不是犯了什么错误,或者其他什么可能是造成这种不同输出的原因。
提前致谢。
最佳答案
与非并发 hashmap 不同的是,如果在迭代时添加内容,并发 map 不会快速失败。
但是,无法保证迭代器(或 get() 方法或任何其他读取操作)何时以及是否会看到新添加/删除的元素。
来自文档:
Iterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration
编辑:
连贯的不同结果背后的原因在于 ConcurrentHashMap 如何组织段并对其进行迭代。
根据键的散列,键被映射到不同的段:
"1" -> 15 "2" -> 0 "3" -> 6 "4" -> 5 "Samsung" -> 7
当一个迭代器被调用时,它从最后一个到第一个迭代段。
因此,在第 0 时刻,迭代器从段 15 开始,在那里它找到键“1”="Windows phone",它首先进入输出。
然后,由于迭代器内部实现,它到达下一个元素,即第 6 段的“3”="HTC"。
此时“S5”的插入就位了。如果 key 是“4”,它将转到第 5 段,如果 key 是“Samsung”,它将转到第 7 段。
在发送“HTC”输出后,它搜索下一个元素。
当key为“4”时,进入第5段,找到“4”="S5",送出输出。
当key为“Samsung”时,进入第7段,已经被迭代器扫描过,发现为空,所以没有找到,直接进入第0段取回“2”=“Iphone” .
这解释了行为。
关于java - 并发 HashMap - 故障安全问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25688963/