fail-fast是Java非线程安全集合在迭代中检测结构修改的机制,通过modCount与expectedModCount比对,不一致则抛ConcurrentModificationException;它不保证线程安全,仅作调试辅助。

Java集合中的fail-fast(快速失败)机制,是一种用于在迭代过程中检测非法结构修改的错误检测策略。它不负责修复问题,而是选择立即中断操作、抛出ConcurrentModificationException,避免程序在数据不一致状态下继续运行,从而暴露潜在bug。
fail-fast触发的核心条件
它只在“使用迭代器遍历集合时,集合结构被意外修改”这一场景下生效。所谓结构修改,是指增删元素(如add()、remove()、clear()),不包括修改已有元素的内容(如list.set(0, "new"))。
- 单线程中也会触发:比如用增强for循环遍历时,直接调用
list.remove() - 多线程中更常见:一个线程正在遍历,另一个线程同时增删元素
- 关键判断依据是
modCount和expectedModCount是否一致——前者由集合维护,每次结构修改+1;后者由迭代器在创建时记录,后续每次调用next()或hasNext()前都会校验
为什么ArrayList、HashMap会触发,而ConcurrentHashMap不会
因为fail-fast不是所有集合的标配,而是java.util包下非线程安全集合的默认行为。它们依赖共享的modCount字段做一致性检查。
-
ArrayList、HashMap、HashSet等都实现了该机制 -
ConcurrentHashMap、CopyOnWriteArrayList等并发容器不使用modCount校验,也不抛这个异常——它们属于fail-safe设计 -
Vector和Stack虽线程安全,但其迭代器仍是fail-fast的(因为内部仍用modCount)
安全修改集合的正确方式
如果必须在遍历中修改,不能绕过迭代器直接操作集合,而应使用迭代器自身提供的方法:
立即学习“Java免费学习笔记(深入)”;
- 用
Iterator.remove()删除当前元素(它会同步更新expectedModCount) - 对
ListIterator还可使用add()或set() - 若需更灵活的增删逻辑,可先收集待操作元素,遍历结束后统一处理
- 多线程场景优先选用
CopyOnWriteArrayList(读多写少)或ConcurrentHashMap(高并发键值操作)
fail-fast不是万能的并发保障
它只是尽力检测,并非严格同步机制。JVM不保证每次并发修改都100%触发异常——比如修改发生在迭代器校验间隙,就可能漏检。因此它本质是调试辅助工具,而非生产环境的线程安全方案。
真正需要并发安全,应从设计层面选用线程安全集合、加锁或采用不可变集合,而不是依赖fail-fast来“兜底”。










