同时向HashMap添加元素

时间:2017-09-09 09:17:09

标签: java string multithreading collections concurrency

如果我迭代标准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线程安全的原因吗?

1 个答案:

答案 0 :(得分:3)

归结为你的新元素添加到哪个哈希桶。在第一个示例中,您的新元素将添加到以后的哈希桶中,而不是您正在处理的哈希桶,以及迭代器尚未到达的哈希桶。在第二个示例中,您的新元素将添加到迭代器已读取的早期哈希桶中。

您应该非常谨慎地在迭代过程中修改集合。在您的情况下,最好将新条目添加到新地图中,然后将它们合并在一起。