ArrayList多线程并发修改会抛ConcurrentModificationException,因其fail-fast机制校验modCount不一致;解决方案首选CopyOnWriteArrayList(读多写少),其次手动加锁,慎用Collections.synchronizedList。

Java 中 ArrayList 本身不是线程安全的,多线程环境下直接并发修改(比如一边遍历一边 add/remove)会抛出 ConcurrentModificationException,这是它最典型的“报错”方式。根本原因在于其 fail-fast 机制 —— 迭代器在创建时会记录集合的修改次数(modCount),后续每次操作都会校验是否被其他线程/代码意外修改。
为什么会报 ConcurrentModificationException?
这不是“随机崩溃”,而是主动检测到不一致后抛出的异常:
- 多个线程同时调用
add()、remove()、clear()等会改变modCount的方法; - 一个线程在用
for-each或显式Iterator遍历时,另一个线程修改了列表结构; - 即使没有真正“并发”,单线程中在迭代过程中自己调用
list.remove()(而非iterator.remove())也会触发。
常见错误写法示例
以下代码在多线程下极大概率抛异常:
// ❌ 危险:多个线程共享同一个 ArrayList 并并发修改
立即学习“Java免费学习笔记(深入)”;
ArrayList<String> list = new ArrayList<>();
// 线程1
new Thread(() -> { for (int i = 0; i < 100; i++) list.add("A" + i); }).start();
// 线程2
new Thread(() -> { for (int i = 0; i < 100; i++) list.add("B" + i); }).start();
// 线程3:边遍历边删
new Thread(() -> {
for (String s : list) { // 此处隐式使用 Iterator
if (s.startsWith("A")) list.remove(s); // ⚠️ 非 iterator.remove() → 报 CME
}
}).start();
四种可靠解决方案(按推荐顺序)
✅ 推荐 1:用 CopyOnWriteArrayList
适合读多写少、遍历频繁、写操作不频繁的场景(如监听器列表、配置快照):
- 每次写操作(add/remove)都新建数组副本,原数组供读线程继续使用;
- 迭代器基于创建时刻的快照,完全不抛
ConcurrentModificationException; - 缺点:内存开销大、写性能差、不支持“弱一致性”更新(迭代器看不到最新写入)。
✅ 推荐 2:手动加锁(synchronized 或 ReentrantLock)
适用于写操作较多、或需要保证强一致性(如银行账户余额计算):
- 对所有访问
ArrayList的代码块加同一把锁; - 确保遍历和修改都在锁内完成,避免“检查后再执行”竞态;
- 注意:不要只锁写操作而放行读操作,否则仍可能看到中间状态或触发 CME。
✅ 推荐 3:改用线程安全的替代容器
根据实际需求选择更合适的结构:
- 如果只是需要线程安全的动态数组语义,且允许一定延迟,可用
CopyOnWriteArrayList; - 如果要支持高频并发读写 + 高效随机访问,考虑
ConcurrentLinkedQueue(但它是队列,无索引); - 如果本质是键值映射,优先用
ConcurrentHashMap; - 若必须用 List 且需高并发写,可封装成带分段锁的自定义结构(较少见)。
⚠️ 不推荐:用 Collections.synchronizedList()
它只是给每个方法加了 synchronized,看似线程安全,但不能解决复合操作的线程安全问题:
- 例如:
if (!list.isEmpty()) list.remove(0);是非原子的 —— 两步之间可能被其他线程插入/删除; - 遍历时仍需手动同步整个迭代过程:
synchronized(list) { for (...) {...} },否则仍会 CME。
一句话总结
ArrayList 多线程报 ConcurrentModificationException 是设计使然,不是 bug;解决核心是“隔离修改”或“串行化访问”。优先选 CopyOnWriteArrayList(读多写少),或用显式锁保障临界区原子性(写多/强一致),避免依赖 synchronizedList 的假安全感。


















