fail-fast机制即为快速失败机制,个人认为是一种防护措施,在集合结构发生改变的时候,使尽全力抛出ConcurrentModificationException,所以该机制大部分用途都是用来检测Bug的;

下面的代码可以引发fail-fast

     public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0 ; i < 10 ; i++ ) {
list.add(i + "");
}
Iterator<String> iterator = list.iterator();
int i = 0 ;
while(iterator.hasNext()) {
if (i == 3) {
list.remove(3);
//list.add("11"); 添加元素同样会引发
}
System.out.println(iterator.next());
i ++;
}
}

fail-fast原理

每个集合都会实现可遍历的接口,以上述代码为例,集合调用iterator();方法的时候,其实是返回了一个new Itr();

    /**
* Returns an iterator over the elements in this list in proper sequence.
*
* <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @return an iterator over the elements in this list in proper sequence
*/
public Iterator<E> iterator() {
return new Itr();
}

以下是Itr源码

    /**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount; public boolean hasNext() {
return cursor != size;
} @SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
} public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
} @Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
} final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

Itr有3个重要属性;

cursor是指集合遍历过程中的即将遍历的元素的索引

lastRet是cursor -1,默认为-1,即不存在上一个时,为-1,它主要用于记录刚刚遍历过的元素的索引。

expectedModCount它初始值就为ArrayList中的modCount(modCount是抽象类AbstractList中的变量,默认为0,而ArrayList 继承了AbstractList ,所以也有这个变量,modCount用于记录集合操作过程中作的修改次数)

由源码可以看出,该异常就是在调用next()的时候引发的,而调用next()方法的时候会先调用checkForComodification(),该方法判断expectedModCount与modCount是否相等,如果不等则抛异常了

那么问题就来了,初始化的时候expectedModCount就被赋值为modCount,而且源码当中就一直没有改变过,所以肯定是modCount的值变了

arrayList继承了abstractList,abstractList有modCount属性,通过以下源码我们可以看到,当ArrayList调用add、remove方法,modCount++

    /**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
} /**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
rangeCheck(index); modCount++;
E oldValue = elementData(index); int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work return oldValue;
}

所以由此可见,对集合的操作中若modCount发生了改变,则会引发fail-fast机制;同时可以看出如果想要移除集合某元素,可以使用迭代器的remove方法,则不会引发fail-fast;

发表该文章也参考了许多另一片文章的内容,详情地址:https://blog.csdn.net/zymx14/article/details/78394464

浅谈fail-fast机制的更多相关文章

  1. 浅谈JVM线程调度机制及主要策略

    在之前有说过线程,应该都知道,所谓线程就是进程中的一个子任务,一个进程有多个线程.今天的话主要就是谈一谈JVM线程调度机制.我们结合线程来说,当我们在做多线程的案例时,如一个经典案例,火车站卖票. * ...

  2. 浅谈java发射机制

    目录 什么是反射 初探 初始化 类 构造函数 属性 方法 总结 思考 什么是反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意 ...

  3. 浅谈java反射机制

    目录 什么是反射 初探 初始化 类 构造函数 属性 方法 总结 思考 什么是反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意 ...

  4. 浅谈android binder机制

    binder机制 是谷歌优化在android上更适合终端的IPC(多进程通信方式),满足系统对通信方式,传输性能和安全性的要求. 特性: 1. 用驱动程序来推进进程间的通信.2. 通过共享内存来提高性 ...

  5. 浅谈Java回调机制

    像许多网上介绍回调机制的文章一样,我这里也以一个现实的例子开头:假设你公司的总经理出差前需要你帮他办件事情,这件事情你需要花些时间去做,这时候总经理肯定不能守着你做完再出差吧,于是就他告诉你他的手机号 ...

  6. 浅谈java编译机制和运行机制

    源文件和字节码的组成方式 源文件: 拓展名后跟java的文件即java的源文件. Java 源码编译由以下三个过程组成: 1.分析和输入到符号表 2.注解处理 3.语义分析和生成class文件 流程图 ...

  7. 浅谈利用同步机制解决Java中的线程安全问题

    我们知道大多数程序都不会是单线程程序,单线程程序的功能非常有限,我们假设一下所有的程序都是单线程程序,那么会带来怎样的结果呢?假如淘宝是单线程程序,一直都只能一个一个用户去访问,你要在网上买东西还得等 ...

  8. 浅谈 java 反射机制

    一:Java反射概念 Java反射是Java被视为动态(或准动态)语言的一个关键性质.这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其mod ...

  9. 浅谈ecmall插件机制

    插件是独立于原系统的程序模块,目的是在不修改原程序的情况下对系统进行扩展,便于修改和管理.目前web开发中大多是使用钩子形式来定义插件, 比较典型的有 wordpress, drupal系统 ecma ...

  10. 浅谈MapReduce工作机制

    1.MapTask工作机制 整个map阶段流程大体如上图所示.简单概述:input File通过getSplits被逻辑切分为多个split文件,通通过RecordReader(默认使用lineRec ...

随机推荐

  1. Struts2学习-ssh框架

    SSH是 struts+spring+hibernate的一个集成框架,是目前比较流行的一种Web应用程序开源框架. http://www.cnblogs.com/laibin/p/5847111.h ...

  2. Windows 实用小工具

    超实用的Windows工具 ====================================================================================== ...

  3. imooc课程:Java高并发秒杀API 记录

    Java高并发秒杀API之业务分析与DAO层 Java高并发秒杀API之Service层 Java高并发秒杀API之web层 Java高并发秒杀API之高并发优化 除了并发部分外的这个web开发的总结 ...

  4. February 2 2017 Week 5 Thursday

    Only do what your heart tells you. 随心而行. My heart tells me that I should leave here and go back to X ...

  5. 看了xici有写给孩子的信,maybe我也要写给孩子一些东西了

    看了xici有写给孩子的信,maybe我也要写给孩子一些东西了

  6. windows 安装redis并注册服务

        windows下载地址 https://github.com/MSOpenTech/redis/releases     启动:redis-server redis.windows.conf ...

  7. UVA12034 Race

    嘟嘟嘟 令dp[i]表示在n个人中,有 i 个人获得第一名的方案数,转移方程为dp[i] = C(i, n) * dp[n - i].C(i, n)就是从n个人中选 i 个第一,那么剩下的n - i ...

  8. MSF入侵安卓手机

    MSF是Metasploit的简称,Metasploit是一款开源的安全漏洞检测工具,非常强大,分别有Windows版和Linux版,工具里集成了许多微软公布的漏洞(0day). 我这里做测试的系统是 ...

  9. Leetcode 225 两个队列实现栈

    Implement the following operations of a stack using queues. push(x) -- Push element x onto stack. po ...

  10. mongo安装跟启动

    mongo下载地址:http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.9.tgz