Java fail-fast 机制

简介: fail-fast 机制,即快速失败机制,是 Java 集合(Collection)中的一种错误检测机制,检测在迭代期间集合被修改的情况。fail-fast 机制并不保证在不同步的修改下一定会抛出异常,它只是尽最大努力去抛出,所以这种机制一般仅用于检测 bug。

简介


  fail-fast 机制,即快速失败机制,是 Java 集合(Collection)中的一种错误检测机制,检测在迭代期间集合被修改的情况。fail-fast 机制并不保证在不同步的修改下一定会抛出异常,它只是尽最大努力去抛出,所以这种机制一般仅用于检测 bug


示例


  在集合中,当直接使用 Iterator 迭代(而不是通过 for-each 循环间接使用),对正在被迭代的集合进行结构上的改变(即对该集合使用 addremove clear 等方法),那么迭代器就不再合法,发生 fail-fast,抛出ConcurrentModificationException异常。

import java.util.*;
public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);list.add(2);list.add(3);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
            list.add(4);// 引起fail-fast 
        }
    }
}


原理


  由以上示例,我们通过ArrayList中的Iterator来剖析 fail-fast 机制原理,分析ArrayList中的Iterator如何实现 fail-fast 机制,如何抛出ConcurrentModificationException异常。


调用iterator() 获取Iterator 对象


  它会返回一个 Itr 类的对象,而 Itr 类是 ArrayList 内部类,实现了 Iterator 接口。

public Iterator<E> iterator() {
    return new Itr();// 返回一个Iterator对象
}

Itr 类的成员变量 expectedModCount


  cursor lastRet 都很好理解,我们需要重点关注 expectedModCount,在此之前,我们先搞清楚 modCount 是什么?
  modCount
ArrayList 的一个成员变量,在 ArrayList 被创建即存在并初始化,modCount 含义为记录从创建后 ArrayList 的修改次数,addremove clear 等方法都会引起 modCount 值的增加。
  
在创建了 Itr 对象时,将 modCount 储存在数据域 expectedModCount 中,可以理解为保存 ArrayList 当前状态。

private class Itr implements Iterator<E> {
  int cursor;    // 下一个返回元素的索引,开始为0
  int lastRet = -1; // 最近返回的元素的索引,没有则为-1
  int expectedModCount = modCount;
  ......
}
public E remove(int index) {// ArrayList的remove方法(截取)
  ......
  modCount++;// 每次调用都会增加modCount的值
  ......
}


Itr 类的成员函数 checkForComodification()


  Itr 类中有一个checkForComodification() 方法,专门用于检测最新的 modCount 是否等于expectedModCount,经过前面的分析,可以知道在 ArrayList 进行addremoveclear 等涉及到修改集合结构的操作时,modCount 就会发生改变(modCount++),所以当使用迭代器时改变集合结构或多线程环境中操作集合,就会使 modCount 发生变化,这样在 checkForComodification 方法中就会抛出ConcurrentModificationException 异常。
  
这样即可检测 ArrayList 的状态是否改变过,如果状态改变就抛出 ConcurrentModificationException异常,这样即实现了fail-fast 机制,通过源码可以看出,每一次 next remove 的调用都会调用 checkForComodification 进行检测。

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}
public E next() {
  ......
    checkForComodification();
  ......
}
public void remove() {
  ......
    checkForComodification();
  ......
}

避免 fail-fast


单线程环境


  在单线程的遍历过程中,如果要进行 addremove 等操作,调用迭代器的 addremove 方法而不是集合类的 addremove 方法。


多线程环境

  在多线程环境中使用 Java 并发包(java.util.concurrent)中对应的类来代替ArrayList HashMap  


     比如使用CopyOnWriterArrayList代替 ArrayList,使用ConcurrentHashMap代替 HashMap

相关文章
|
24天前
|
安全 Java
深入Java并发编程:线程同步与互斥机制
【4月更文挑战第6天】Java并发编程中,确保数据一致性与防止条件竞争是关键。语言提供`synchronized`关键字、`Lock`接口和原子变量等机制处理并发问题。线程同步问题包括竞态条件、死锁和活锁。`synchronized`实现内置锁,`Lock`接口提供更灵活的锁管理,原子变量则支持无锁安全操作。理解并恰当使用这些工具能有效管理并发,避免数据不一致。
|
2月前
|
Java
Java并发编程中的锁机制
【2月更文挑战第22天】 在Java并发编程中,锁机制是一种重要的同步手段,用于保证多个线程在访问共享资源时的安全性。本文将介绍Java锁机制的基本概念、种类以及使用方法,帮助读者深入理解并发编程中的锁机制。
|
2月前
|
Java 程序员
Java中的异常处理机制
【2月更文挑战第22天】在Java编程中,异常处理是一个重要的概念。它允许程序员在程序执行过程中遇到错误时,对错误进行处理,而不是让程序崩溃。本文将介绍Java中的异常处理机制,包括异常的分类、如何捕获和处理异常以及自定义异常等内容。
|
2月前
|
存储 Java 数据库
|
2月前
|
Java
深入了解Java中的锁机制
深入了解Java中的锁机制
|
2月前
|
Java 程序员 编译器
认识Java 的反射机制
反射Reflection被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。反射是一种功能强大且复杂的机制。使用它的主要人员是工具构造者,而不是应用程序员。
29 5
|
2月前
|
开发框架 Java API
java反射机制的原理与简单使用
java反射机制的原理与简单使用
17 1
|
3天前
|
Java
【专栏】Java中的反射机制与应用实例
【4月更文挑战第27天】本文探讨了Java反射机制,该机制允许程序在运行时获取类信息、动态创建对象、调用方法和访问属性。反射通过Class、Constructor、Method和Field类实现。文中列举了反射的应用场景,如动态创建对象、调用方法、访问属性和处理注解,并提供了相关实例代码演示。
|
2月前
|
存储 安全 Java
【深度挖掘Java并发编程底层源码】「底层技术原理体系」带你零基础认识和分析学习相关的异步任务提交机制FutureTask的底层原理
【深度挖掘Java并发编程底层源码】「底层技术原理体系」带你零基础认识和分析学习相关的异步任务提交机制FutureTask的底层原理
14 0
|
1天前
|
敏捷开发 机器学习/深度学习 Java
Java中的异常处理机制深入理解与实践:持续集成在软件测试中的应用探索自动化测试在敏捷开发中的关键作用
【4月更文挑战第29天】在Java编程中,异常处理是一个重要的概念。它允许开发者在程序执行过程中遇到错误或异常情况时,能够捕获并处理这些异常,从而保证程序的稳定运行。本文将详细介绍Java中的异常处理机制,包括异常的分类、异常的处理方式以及自定义异常等内容。 【4月更文挑战第29天】 随着敏捷开发和DevOps文化的兴起,持续集成(CI)已成为现代软件开发周期中不可或缺的一环。本文将探讨持续集成在软件测试领域内的关键作用、实施策略以及面临的挑战。通过对自动化构建、测试用例管理、及时反馈等核心要素的详细分析,揭示持续集成如何提高软件质量和加速交付过程。 【4月更文挑战第29天】 在当今快速发