ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java fail-fast 机制

2022-01-23 02:00:06  阅读:159  来源: 互联网

标签:Java Iterator ArrayList fast modCount add remove fail


简介

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

示例

  在集合中,当直接使用 Iterator 迭代(而不是通过 for-each 循环间接使用),对正在被迭代的集合进行结构上的改变(即对该集合使用 add、remove 或 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 的修改次数,add、remove 、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 进行add,remove,clear 等涉及到修改集合结构的操作时,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

单线程环境

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

多线程环境

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

标签:Java,Iterator,ArrayList,fast,modCount,add,remove,fail
来源: https://www.cnblogs.com/Acx7/p/15835628.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有