如果我迭代标准HashMap
并尝试在迭代时向其添加元素,我会ConcurrentModificationException
。
所以我尝试了一个允许并发添加的HashMap:
ConcurrentHashMap<String, Integer> cMap = new ConcurrentHashMap<>();
cMap.put("one", 1);
cMap.forEach((key, value) -> cMap.put(key + key, value + value));
System.out.println(cMap);
但是,生成的地图有点奇怪:
{oneoneoneoneoneoneoneone=8, one=1, oneone=2, oneoneoneone=4}
如果将密钥更改为zx(cMap.put("zx", 1)
),结果现在为:
{zxzx=2, zx=1}
问题:
1)为什么会这样?两个并发操作(迭代和添加)不应该冲突。
2)如何解决不一致问题?
与Collections相反,在迭代String的chars时更改String时,不会遇到此问题:
String str = scanner.next();
for (int i = 1; i < str.length(); i++) {
if (str.charAt(i) == str.charAt(i-1)) {
str = str.substring(0, i-1) + str.substring(i+1);
i = 0;
}
}
if (str.length() == 0) {
System.out.println("Empty String");
} else {
System.out.println (str);
}
}
请注意,在上面的循环中,源字符串实际上没有被更改,但是因为String是不可变的而无法修改而重新分配。
以上代码运行良好且一致。这是Strings线程安全的原因吗?
答案 0 :(得分:3)
归结为你的新元素添加到哪个哈希桶。在第一个示例中,您的新元素将添加到以后的哈希桶中,而不是您正在处理的哈希桶,以及迭代器尚未到达的哈希桶。在第二个示例中,您的新元素将添加到迭代器已读取的早期哈希桶中。
您应该非常谨慎地在迭代过程中修改集合。在您的情况下,最好将新条目添加到新地图中,然后将它们合并在一起。