Fail Fast and Fail Safe Iterator in Java2025 年 5 月 2 日 | 阅读 6 分钟 Java 中的迭代器是 Java 集合框架的一部分。它们用于逐个检索元素。Java Collection 支持两种类型的迭代器:快速失败(Fail Fast)和安全失败(Fail Safe)。这些迭代器在异常处理中非常有用。 快速失败迭代器会在暴露失败时立即中止操作,并停止整个操作。相比之下,安全失败迭代器在发生故障时不会中止操作。相反,它会尽可能地避免失败。 在本节中,我们将通过示例讨论快速失败迭代器和安全失败迭代器。此外,我们将了解它们之间的区别。 在理解快速失败和安全失败迭代器之前,让我们先了解并发修改。 并发修改 Java 中的并发修改是指在另一个任务正在处理某个对象时,同时修改该对象。简单来说,并发修改是在另一个线程正在处理对象时修改它们的过程。它会改变数据集合的结构,通过移除、添加或更新集合中元素的值。 并非所有迭代器都支持此行为;某些迭代器的实现可能会抛出 ConcurrentModificationException。 让我们来理解快速失败和安全失败系统。 快速失败和安全失败系统 快速失败系统是一种在报告错误后立即关闭的系统。其中的所有操作都会立即中止。 安全失败系统是一种即使在发生错误或故障后仍能继续运行的系统。这些系统不会立即中止操作;相反,它们会尝试隐藏错误,并尽可能地避免失败。 快速失败迭代器Java 中的迭代器用于遍历集合的对象。集合返回两种类型的迭代器,要么是快速失败,要么是安全失败。 如果集合的结构被修改,快速失败迭代器会立即抛出 ConcurrentModificationException。结构修改是指在另一个线程遍历集合时,向数据集合中添加、移除或更新元素的值。快速失败迭代器的一些示例包括 ArrayList、HashMap 集合类的迭代器。 工作原理 快速失败迭代器使用一个名为 **modCount** 的内部标志来了解集合的状态,即集合是否已在结构上被修改。每次集合被修改时,modCount 标志都会更新;它会检查下一个值;如果找到,则在创建此迭代器后,modCount 将被修改。它将抛出 ConcurrentModificationException。 请看下面的示例,以理解快速失败迭代器的行为。 输出 LA Exception in thread "main" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode(HashMap.java:1445) at java.util.HashMap$KeyIterator.next(HashMap.java:1469) at FailFastDemo.main(FailFastDemo.java:14) 从上面的输出,我们可以注意到以下几点:
安全失败迭代器安全失败迭代器与快速失败迭代器正好相反;与它们不同的是,安全失败迭代器不会抛出任何异常,除非它可以在迭代过程中处理集合的修改。这是因为它们操作的是集合对象的副本,而不是原始对象。对原始集合进行的结构性更改会被它们忽略,并影响副本集合,而不是原始集合。因此,原始集合将保持结构不变。 然而,Java SE 文档中并没有“安全失败”这个实际的词语;相反,安全失败被称作非快速失败迭代器。 让我们通过一些示例来理解它的行为。 FailSafeDemo.java 输出 1 7 9 11 从上面的示例中,我们可以看到集合在另一个线程打印结果的同时进行迭代。输出不受其他操作的影响;这意味着创建了集合的独立副本,并在其上执行迭代。 但是,并非所有不使用快速失败迭代器的集合都会创建它的克隆或副本以避免 ConcurrentModificationException。例如,ConcurrentHashMap 不操作对象的独立副本,尽管它不是快速失败的。相反,它使用规范指定为非快速失败迭代器的语义。 考虑下面的示例 FailSafeDemo1.java 输出 EIGHT : 8 FIVE : 5 NINE : 9 ONE : 1 SEVEN : 7 从上面的示例中,我们可以看到我们在另一个线程执行操作的同时正在迭代集合。迭代结果被放置在同一个集合中,这意味着它没有创建对象的独立副本,也没有抛出任何 ConcurrentModificationException。 从上面的示例中,我们可以注意到关于安全失败迭代器的以下几点:
快速失败和安全失败迭代器之间的区别快速失败和安全失败迭代器之间的主要区别在于,安全失败在迭代过程中修改对象时不会抛出任何 ConcurrentModificationException,而快速失败则在这种情况下会抛出异常。这是因为安全失败迭代器操作的是克隆的集合,而不是原始集合。 在不同参数的基础上,它们之间还有一些其他比较。让我们来讨论一下。
|
在编程中,将一种类型转换为另一种类型(或反之)是一项至关重要的任务。有时我们需要将一种类型转换为另一种类型。在 Java 转换部分,我们讨论了各种类型的转换。在本节中,我们可以讨论如何将二进制转换为...
5 分钟阅读
? 从当前日期计算周数是各种 Java 应用程序中的常见要求。周数计算在调度、时间跟踪、工资管理以及许多其他场景中非常有用。Java 提供了多种方法来从当前日期计算周数,使用内置的...
阅读 4 分钟
格雷码(Grey Code)以弗兰克·格雷(Frank Grey)的名字命名,是一种二进制数制系统,其中两个连续值之间只有一个比特位的差异。它也被称为“反射二进制码”,因为它的 (n-1) 位形式可以被反射并附加到自身...
阅读 4 分钟
使用 StrictMath.scalb() 函数可以在 Java 中快速有效地计算浮点数乘以二的幂的值。作为 java.lang.StrictMath 类的一部分,该方法在各种平台上比 java.lang.Math 类产生更一致的结果,因为它包含一个...
5 分钟阅读
在 Java 中,不可变类可以定义为,当它的对象被创建时,它的内容就不能再被改变。Java 中的所有包装类,如 Integer、Boolean、Byte、Short 都是不可变的。在 Java 中,不可变类以提供各种优势而闻名……
5 分钟阅读
N 级楼梯问题,也称为楼梯爬升问题。这是一个经典的动态规划挑战。该问题通常询问:给定一个楼梯,有多少种不同的方法可以爬到顶部?如果你只能爬一两个台阶……
7 分钟阅读
计数排序是 Java 中最常用的排序技术之一,它基于特定范围内的键。计数排序不通过比较元素来执行排序。它通过计数具有不同键值的对象来执行排序,例如哈希。之后,它执行一些...
阅读 4 分钟
给定一个具有 N 行 M 列的二维数组 ARR,其中每个元素都包含 0 或 1 的值,将给定的矩阵转换为一个“好”矩阵。在“好”矩阵中,如果一个元素为 0,则其行和列中的所有元素都应...
5 分钟阅读
复合赋值运算符是将多个运算符组合在一起。它包括一个赋值运算符和一个算术运算符或按位运算符。在右操作数和左操作数之间执行指定的运算,并将结果赋给左操作数……
7 分钟阅读
我们可以通过 reverse()、split()、toLowerCase()、toUpperCase() 和 substring() 方法来反转字符串中每个单词的大小写。通过 split("\\s") 方法,我们可以将所有单词获取到一个数组中。要获取第一个字符,我们可以使用 substring() 或 charAt()...
阅读1分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India