1. 引言
本文将深入探讨Java中两种重要的迭代器机制:Fail-Fast迭代器和Fail-Safe迭代器。
- Fail-Fast系统:一旦检测到异常立即中止操作,快速暴露问题并终止整个流程
- Fail-Safe系统:遇到异常时不会中止操作,尽可能避免抛出异常
这两种机制在并发场景下的表现差异显著,理解它们的区别对编写健壮的并发代码至关重要。
2. Fail-Fast迭代器
Java中的Fail-Fast迭代器在底层集合被修改时会立即"罢工"。
工作原理
集合内部维护一个计数器modCount
:
- 每次添加/删除元素时,
modCount
递增 - 迭代时每次调用
next()
都会比较当前modCount
与初始值 - 不匹配时抛出
ConcurrentModificationException
,终止整个操作
✅ 典型代表:java.util
包下的集合(如ArrayList
、HashMap
等)的默认迭代器
ArrayList<Integer> numbers = // ...
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
Integer number = iterator.next();
numbers.add(50); // 触发ConcurrentModificationException
}
⚠️ 重要特性:
- 非绝对保证:并发修改时行为不可预测,仅尽力抛出异常
- 安全删除:使用迭代器的
remove()
方法删除元素是安全的 - 危险操作:直接调用集合的
remove()
方法会触发异常
ArrayList<Integer> numbers = // ...
// 安全操作示例
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
if (iterator.next() == 30) {
iterator.remove(); // ✅ 安全
}
}
// 危险操作示例
iterator = numbers.iterator();
while (iterator.hasNext()) {
if (iterator.next() == 40) {
numbers.remove(2); // ❌ 抛出ConcurrentModificationException
}
}
3. Fail-Safe迭代器
Fail-Safe迭代器优先保证操作不中断,避免异常处理带来的麻烦。
工作机制
- 创建集合的克隆副本进行迭代
- 原集合修改不影响迭代副本
- 即使集合被修改,迭代仍继续执行
⚠️ 术语澄清:严格来说不存在真正的"Fail-Safe",更准确的术语是弱一致性(Weakly Consistent)
✅ 典型代表:java.util.concurrent
包下的集合(如ConcurrentHashMap
、CopyOnWriteArrayList
等)
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("First", 10);
map.put("Second", 20);
map.put("Third", 30);
map.put("Fourth", 40);
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
map.put("Fifth", 50); // ✅ 不会抛出异常
}
关键特性
- 数据一致性:迭代器可能反映也可能不反映集合的修改(取决于具体实现)
- 性能开销:创建集合副本带来额外的时间和内存消耗
- 数据滞后:迭代的是副本而非原集合,可能无法获取最新数据
📌 ConcurrentHashMap的特殊行为:
// 上述代码中迭代会执行5次
// 因为ConcurrentHashMap的迭代器是弱一致的
// 可能(但不保证)反映迭代器创建后的修改
4. 总结
通过本文我们深入理解了两种迭代器机制的核心差异:
特性 | Fail-Fast迭代器 | Fail-Safe迭代器 |
---|---|---|
异常处理 | 立即抛出ConcurrentModificationException |
不抛出异常 |
数据一致性 | 强一致性 | 弱一致性 |
性能开销 | 低 | 高(需创建副本) |
典型实现 | ArrayList , HashMap 等 |
ConcurrentHashMap 等并发集合 |
适用场景 | 单线程或严格同步环境 | 高并发修改场景 |
💡 开发建议:
- 单线程环境优先使用Fail-Fast迭代器(性能更好)
- 高并发修改场景选择Fail-Safe迭代器(避免异常中断)
- 谨慎处理迭代过程中的集合修改,优先使用迭代器提供的修改方法
掌握这两种迭代器的行为差异,能帮助我们在并发编程中避免常见陷阱,编写更健壮的代码。