在 Java 开发中,迭代器是用于遍历集合(如
List
、
Set
等)元素的工具。而
fail-fast
和
fail-safe
是两种不同的迭代器设计策略,它们在处理集合并发修改时有着不同的行为。下面将详细介绍这两种策略。
fail-fast 策略
概念
fail-fast
是 Java 集合框架中许多迭代器(如 ArrayList
、HashMap
等的迭代器)所采用的一种错误检测机制。当一个集合在使用迭代器进行遍历的过程中被其他线程或当前线程以非迭代器允许的方式进行了结构性修改(例如添加、删除元素)时,迭代器会立即抛出 ConcurrentModificationException
异常,从而快速失败,避免程序在不一致的状态下继续运行。
原理
fail-fast
迭代器通过一个名为 modCount
的计数器来实现。在集合类中,每次进行结构性修改时,modCount
的值都会增加。迭代器在创建时会记录当前的 modCount
值,在每次调用 next()
方法时,会检查集合的 modCount
值是否与迭代器记录的 modCount
值相同。如果不同,说明集合被修改过,就会抛出 ConcurrentModificationException
异常。
示例代码
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class FailFastExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("cherry");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
// 非迭代器方式修改集合,会触发 fail-fast
list.add("date");
}
}
}
执行结果:
代码解释
在上述代码中,我们创建了一个 ArrayList
并添加了三个元素。然后使用迭代器遍历集合,在遍历过程中,我们使用 list.add("date")
方法对集合进行了结构性修改,这会导致 modCount
值改变。当迭代器调用 next()
方法时,会检测到 modCount
值不一致,从而抛出 ConcurrentModificationException
异常。
需要注意的是,增强 for 循环同样也会抛出抛出 ConcurrentModificationException
异常。例如将上例代码修改为:
for (String element : list) {
System.out.println(element);
// 非迭代器方式修改集合,会触发 fail-fast
list.add("date");
}
fail-safe 策略
概念
fail-safe
迭代器在遍历集合时,会创建集合的一个副本,迭代器遍历的是这个副本,而不是原始集合。因此,即使原始集合在迭代过程中被修改,也不会影响迭代器的遍历,不会抛出 ConcurrentModificationException
异常。
原理
fail-safe
迭代器通过复制原始集合的内容来实现。在创建迭代器时,会将原始集合的元素复制到一个新的数据结构中,迭代器在这个副本上进行遍历。由于副本和原始集合是相互独立的,所以对原始集合的修改不会影响迭代器的遍历。
示例代码
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.Iterator;
public class FailSafeExample {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("apple");
list.add("banana");
list.add("cherry");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
// 修改原始集合,不会影响迭代器遍历
list.add("date");
}
}
}
执行结果:
代码解释
在上述代码中,我们使用了 CopyOnWriteArrayList
,它是一个支持 fail-safe
迭代器的集合类。在迭代过程中,我们使用 list.add("date")
方法对原始集合进行了结构性修改,但由于迭代器遍历的是集合的副本,所以不会抛出 ConcurrentModificationException
异常。