You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Iterator仍抛出ConcurrentModificationException的原因排查

问题分析与解决方案

兄弟,这个ConcurrentModificationException在多线程操作Map的时候太常见了,我来给你捋清楚原因和解决办法:

为什么会抛出这个异常?

首先得搞懂两个核心点:

  1. Collections.synchronizedMap(new HashMap<>())只是给HashMap的单个方法加了同步锁,但复合操作(比如遍历+修改/添加)并不是原子的。也就是说,调用iterator()、hasNext()、next()这些方法时,虽然每个方法本身是同步的,但方法之间的间隙还是会让其他线程有机可乘。
  2. HashMap的Iterator是fail-fast机制:当Iterator启动后,如果Map的结构被修改(比如添加、删除元素,除了Iterator自己的remove()方法),Iterator就会抛出这个异常,防止你拿到不一致的数据。

结合你的场景拆解:

  • 最初的代码里,你在遍历的时候同时调用了it.remove()和unordered.remove(id)——这相当于用Iterator移除元素后,又用Map本身的方法再次修改结构,直接导致Map维护的modCount(结构修改次数)和Iterator预期的expectedModCount不一致,触发异常。
  • 后来你删掉了unordered.remove(id),但还是报错,这是因为你提到的遍历期间有其他线程在给unordered添加新元素。其他线程调用unordered.put()会修改Map的modCount,而当前遍历的Iterator没感知到这个变化,自然还是会抛出异常。

解决办法

方案1:换成ConcurrentHashMap(最推荐)

直接把Collections.synchronizedMap(new HashMap<>())换成ConcurrentHashMap<String, byte[]>(),这是最省心的方式:

Map<String, byte[]> unordered = new ConcurrentHashMap<>();

ConcurrentHashMap的Iterator是弱一致的,不会因为其他线程的修改而抛出ConcurrentModificationException,而且它本身就原生支持并发的读写、修改操作,完美适配你的多线程场景(服务器+客户端并发操作)。

方案2:给遍历+修改的整个过程加锁(如果不想换Map实现)

如果你非要用synchronizedMap,那必须手动给整个遍历和修改的代码块加锁,确保这段时间内没有其他线程能修改unordered的结构:

// 给unordered对象加锁,确保遍历期间其他线程无法修改它
synchronized(unordered) {
    int tam = 0;
    if (unordered.size() <= maxOrderSize) {
        tam = unordered.size();
    } else {
        tam = maxOrderSize;
    }
    HashMap<String, byte[]> prop = new HashMap<>(tam);
    Iterator<String> it = unordered.keySet().iterator();
    for (int i = 0; i < tam; i++) {
        if (it.hasNext()) {
            String id = it.next();
            prop.put(id, unordered.get(id));
            it.remove(); // 只能用Iterator的remove方法修改结构
        }
    }
}

这样,在锁持有期间,其他线程调用put()或者remove()都会被阻塞,直到当前线程完成遍历和修改,Iterator就不会检测到意外的结构变化了。

内容的提问来源于stack exchange,提问作者hunter32

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:11:12