增强for循环在编译期被转为基于Iterator的while循环;Collections.synchronizedList的iterator()不加锁,仅靠modCount做fail-fast校验;不同集合迭代器行为各异:ArrayList强一致、CopyOnWriteArrayList基于快照、ConcurrentHashMap.KeySetView弱一致。

增强 for 循环(for (Type e : collection))在编译期会被 Java 编译器自动转成基于 Iterator 的显式遍历代码,这个过程是隐式的、不可见的,但逻辑清晰且严格遵循规范。
编译器如何翻译增强 for 循环
Java 规范要求:只要集合类型实现了 Iterable 接口(如 ArrayList、HashSet、CopyOnWriteArrayList),编译器就会调用其 iterator() 方法获取迭代器,并用 hasNext() 和 next() 构建 while 循环结构。
例如这段代码:
for (String s : list) {System.out.println(s);
}
等价于手动写的:
立即学习“Java免费学习笔记(深入)”;
Iteratorwhile (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
为什么 iterator() 方法本身不加锁
Collections.synchronizedList 返回的包装类,只对 add、remove、get 等单步操作做了同步,但 iterator() 方法返回的是底层原始 ArrayList 的迭代器——它不持有锁,也不检查外部同步状态。
- 该迭代器仅依赖
modCount做快速失败(fail-fast)校验 - 一旦其他线程在遍历中途修改了列表结构,
next()就可能抛ConcurrentModificationException - 即使你用
synchronized(list)包住整个 for-each 块,也必须确保iterator()调用和后续遍历都在同一把锁下
不同集合的迭代器行为差异
不是所有 iterator() 都表现一致。关键看底层实现机制:
-
ArrayList迭代器:强一致性 + fail-fast,结构变更立即报错 -
CopyOnWriteArrayList迭代器:基于快照,遍历时完全隔离写操作,不会报异常,但看不到新增/删除项 -
ConcurrentHashMap.KeySetView迭代器:弱一致性,可能跳过或重复某些元素,但不抛异常
安全遍历的实践要点
若需线程安全遍历,不能只靠 synchronizedList,得配合使用方式:
- 显式加锁:用
synchronized(list) { for (e : list) { ... } } - 用快照型集合:如
CopyOnWriteArrayList,适合读多写少场景 - 避免在遍历中调用
list.remove()或list.add()—— 增强 for 循环本身就不支持边遍历边结构性修改 - 真要删元素,改用
Iterator.remove(),这是唯一被允许的遍历时删除方式


















