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

Java遍历列表时触发ConcurrentModificationException问题求助

解决遍历列表时的ConcurrentModificationException问题

首先,咱们得先搞清楚ConcurrentModificationException的核心触发逻辑:当你用迭代器(包括增强for循环底层的迭代器)遍历一个非线程安全集合(比如ArrayList)时,如果集合在迭代器创建之后被修改了(增、删元素,或者修改容量),迭代器的快速失败机制就会抛出这个异常——哪怕修改操作不是在当前循环里执行的,只要迭代器还没走完,集合被改了就会触发异常。

结合你的情况,虽然removeDeads不在循环内部,但可能触发异常的场景有这些:

  • 多线程并发修改:如果removeDeads是在另一个线程中被调用的,而当前线程正在遍历列表,两个线程同时操作同一个非线程安全集合,必然会触发这个异常。毕竟ArrayList这类集合本身没有线程安全保障,迭代器也不支持并发修改。
  • 单线程下的隐式并发修改:哪怕是同一个线程,如果你在遍历过程中(比如增强for循环还没结束的时候),间接调用了removeDeads修改了列表,也会触发异常。比如你的决策逻辑里某个分支触发了removeDeads,或者遍历过程中有其他回调、异步任务调用了这个方法。

给你几个具体的排查和解决方向:

  1. 先确认遍历方式
    如果你用的是增强for循环:

    for (Individual individual : individualList) {
        // 你的决策逻辑
    }
    

    可以换成显式迭代器遍历的写法,同时避免直接修改原集合:

    Iterator<Individual> iterator = individualList.iterator();
    while (iterator.hasNext()) {
        Individual ind = iterator.next();
        // 决策逻辑
        // 注意:如果需要删除当前元素,要用iterator.remove(),而非直接调用集合的remove方法
    }
    
  2. 排查removeDeads的调用时机
    打印日志或者加断点,看看removeDeads是不是在遍历列表的过程中被执行了。如果是单线程里的问题,调整执行顺序:先完成遍历决策,再调用removeDeads修改列表。

  3. 线程安全方案
    如果是多线程场景:

    • 给集合的操作加锁,比如在遍历和removeDeads方法里都用synchronized块包裹:
      synchronized (individualList) {
          // 遍历逻辑
      }
      
      // removeDeads方法里也加锁
      public void removeDeads() {
          synchronized (individualList) {
              // 删除操作
          }
      }
      
    • 换成线程安全的集合,比如CopyOnWriteArrayList——它会在修改时创建一个新的数组副本,迭代器遍历的是旧副本,不会触发ConcurrentModificationException,适合读多写少的场景。
  4. 快速验证方法
    临时把集合换成CopyOnWriteArrayList,如果异常消失了,说明确实是并发修改或者遍历期间修改的问题,再针对性优化。

内容的提问来源于stack exchange,提问作者Timothée Neitthoffer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:11:44