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

Java多线程并发排序迭代ArrayList时ConcurrentModificationException异常触发时机的疑问

为什么一个线程完成迭代会导致另一个线程的迭代抛出ConcurrentModificationException?

这是个非常典型的并发场景问题,核心在于ArrayList的快速失败(fail-fast)迭代器机制,以及线程不安全集合在多线程下的状态共享问题,咱们一步步拆解清楚:

1. 先搞懂ArrayList迭代器的fail-fast逻辑

ArrayList的内置迭代器(ArrayList$Itr)是基于"修改次数"实现快速失败的:

  • ArrayList内部维护一个modCount变量,记录列表的结构性修改次数(比如添加、删除元素,甚至排序——因为排序会重新排列元素数组,属于结构变更)。
  • 当你调用iterator()创建迭代器时,迭代器会把当前的modCount值保存到自己的expectedModCount变量里。
  • 之后每次调用iterator.next()时,都会检查modCount是否等于expectedModCount:如果不等,说明列表在迭代过程中被修改了(不管是当前线程还是其他线程),直接抛出ConcurrentModificationException。

2. 排序操作会修改modCount

你调用的Collections.sort(numbers),底层会委托给ArrayList.sort()方法,而这个方法的实现里明确会递增modCount:

public void sort(Comparator<? super E> c) {
    modCount++;
    Arrays.sort((E[]) elementData, 0, size, c);
}

也就是说,每次执行sort操作,ArrayList的modCount都会+1,而且排序过程中还会直接修改底层的元素数组。

3. 你的线程执行顺序是关键

从输出的日志顺序,我们可以还原真实的执行流程(这也是你产生误解的核心):

  1. Thread-0进入run方法,打印"Going to sort",开始执行sort操作。
  2. Thread-1进入run方法,打印"Going to sort",也开始执行sort操作。
  3. Thread-0的sort先执行完成,打印"Going to iterate",创建迭代器(此时迭代器的expectedModCount等于当前的modCount),开始迭代打印0。
  4. 此时Thread-1的sort还在执行中——因为Thread-1的"Going to iterate"日志是在Thread-0抛异常之后才打印的。
  5. Thread-1的sort执行过程中,会修改ArrayList的modCount(+1),同时修改底层元素数组。
  6. Thread-0的迭代器在调用next()时,检测到modCount已经不等于自己保存的expectedModCount,立刻抛出ConcurrentModificationException。
  7. Thread-1的sort执行完成,打印"Going to iterate",创建迭代器(此时modCount已经稳定,没有其他线程再修改列表),顺利完成迭代打印1。

4. 为什么Thread-1的迭代能正常完成?

因为Thread-1开始迭代时,所有可能修改列表的操作(两个线程的sort)都已经完成了,没有其他线程再去修改ArrayList的modCount或元素数组,所以它的迭代器每次检查modCount和expectedModCount都是相等的,不会触发异常。

总结

你之前误以为两个线程都完成sort后才开始迭代,但实际执行顺序是:Thread-0在Thread-1还没完成sort时就启动了迭代,而Thread-1的sort操作在Thread-0迭代过程中修改了ArrayList的modCount,触发了迭代器的快速失败机制。

另外要记住:ArrayList本身不是线程安全的集合,不要在多线程环境下直接对它进行并发的修改或读写操作,否则会出现各种不可预期的行为(包括这种延迟触发的异常,甚至数据损坏)。如果需要并发操作,建议使用CopyOnWriteArrayList这类线程安全的集合,或者手动加锁保护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 17:42:40