[接] 怎么用 Java 的并发类 ConcurrentHashMap 抛出 ConcurrentModificationException?

2022-10-15 16:33:25 +08:00
 nnegier

For aggregate operations such as putAll and clear, concurrent retrievals may reflect insertion or removal of only some entries. Similarly, Iterators, Spliterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration. They do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html

经 V 友提醒,去看了下 javadoc ,然后发现了这句描述,于是决定复现:

public class Main {

    private static ConcurrentHashMap<String,String> concurrentHashMap = new ConcurrentHashMap<>();

    public static void main(String[] args) {

        for(int i = 0 ; i < 100000 ; i++){
            concurrentHashMap.put("Key"+i,"Value"+i);
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (Map.Entry<String, String> entry : concurrentHashMap.entrySet()){
                    System.out.println("1key:"+entry.getKey()+",value:"+entry.getValue());
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (Map.Entry<String, String> entry : concurrentHashMap.entrySet()){
                    System.out.println("2key:"+entry.getKey()+",value:"+entry.getValue());
                }
            }
        }).start();

        new Thread(new Runnable() {

结果还是没有任何问题。然后我还有用线程在这个多线程遍历的同时去给其增加删除元素,量级也是 10 万,因为客户手机文件也差不多这个数量,结果还是没问题。

所以我想问一下,有办法复现吗?

1260 次点击
所在节点    程序员
5 条回复
DonaldY
2022-10-15 17:04:52 +08:00
ConcurrentHashMap 不会出现 ConcurrentModificationException 。

代码里都没有抛这个异常。

next 指针用 volatile 修饰的,可见。
LeegoYih
2022-10-15 17:35:13 +08:00
HashMap 修改数据时会修改 modCount 的值,遍历时发现 modCount 不一致说明存在另一个线程在修改数据,所以会抛出 ConcurrentModificationException

ConcurrentHashMap 文档上写了 They do not throw ConcurrentModificationException. 这也是符合预期的,如果别人一直在修改数据,我这边遍历一直报错,还让不让人看数据了。

后面 However 只是解释了 iterators 设计之初是为了单个线程遍历的,所以对 ConcurrentHashMap 遍历、size, isEmpty 和 containsValue 等操作只试用于监控或估计的目的,不能用来当做流程控制 /程序控制
Jooooooooo
2022-10-15 17:43:05 +08:00
They do not throw ConcurrentModificationException.

这不是 do not 吗? 你咋复现.
nnegier
2022-10-15 23:01:28 +08:00
@DonaldY 那 CopyOnWriteArraySet 会抛这个 ConcurrentModificationException 异常吗?我去看了代码也没有这个异常。但确实我数据存放类里面有这个问题日志,还很多,上千次
DonaldY
2022-10-16 10:43:53 +08:00
@nnegier 看源码,CopyOnWriteArraySet 底层创建时候使用的是 CopyOnWriteArrayList 。CopyOnWriteArrayList 里面就有抛 ConcurrentModificationException

public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/887146

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX