JDK 实现原理:迭代器策略之 fail-fast 与 fail-safe


在 Java 开发中,迭代器是用于遍历集合(如 ListSet 等)元素的工具。而 fail-fastfail-safe是两种不同的迭代器设计策略,它们在处理集合并发修改时有着不同的行为。下面将详细介绍这两种策略。

fail-fast 策略

概念

fail-fast 是 Java 集合框架中许多迭代器(如 ArrayListHashMap 等的迭代器)所采用的一种错误检测机制。当一个集合在使用迭代器进行遍历的过程中被其他线程或当前线程以非迭代器允许的方式进行了结构性修改(例如添加、删除元素)时,迭代器会立即抛出 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 异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值