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

Java中使用CopyOnWriteArrayList的forEach方法是否会引发ConcurrentModificationException?

为什么CopyOnWriteArrayList的forEach方法在并发写入时不会抛出ConcurrentModificationException?

好问题!咱们得先从CopyOnWriteArrayList的核心设计理念——写时复制(Copy-On-Write)——说起,这是理解它所有并发行为的关键。

先看你贴出来的Java 11中forEach的实现:

public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    for (Object x : getArray()) {
        @SuppressWarnings("unchecked")
        E e = (E) x;
        action.accept(e);
    }
}

你观察得很仔细:这个方法确实没有加任何锁,只是通过getArray()拿到当前数组的引用,然后直接遍历。那为什么并发执行add()或remove()这类写操作时,不会抛出ConcurrentModificationException呢?

原因就在CopyOnWriteArrayList的写操作逻辑上:当你调用写方法时,它并不会直接修改原数组,而是创建一个全新的数组副本,在这个新数组上完成添加/删除操作,最后再把原数组的引用替换成新数组。而forEach方法在调用getArray()的那一刻,就拿到了当时的数组快照——哪怕之后有写操作修改了数组引用,正在进行的遍历依然在操作旧数组,和新数组完全隔离,根本不会触发并发修改的检测。

你提到和iterator()方法的区别,其实两者本质是一致的:CopyOnWriteArrayList的迭代器同样是**fail-safe(安全失败)**的,它持有迭代器创建时的数组快照,遍历过程中也不会因为并发写操作抛出异常。只不过forEach是直接遍历快照数组,而iterator()是把快照封装成了迭代器对象而已。

总结一下:在调用forEach的同时并发执行写操作,绝对不会引发ConcurrentModificationException。因为遍历的是调用瞬间的数组快照,写操作只会修改新数组,两者互不干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 21:39:09