遗嘱-java调集中常见反常fail-fast(面试常问)

今日来看java调集中一个常见的过错机制fail-fast机制。呈现在这个过错机制的实质便是因为单线程和多线程的不同。下面就好遗嘱-java调集中常见反常fail-fast(面试常问)美观一下这个机制是怎样是呈现的。

一、知道fail-fast

今日在运转项意图时分,忽然就呈现了ConcurrentModificationException反常。原因是多线程中运用的,因为在多线程中运用了ArrayList,造成了这么一个反常。这是今日所讲的调集的fai-fast机制。

咱们先来看看维基百科中的解说:

在体系规划中,快速失效体系一种能够当即陈述任何或许标明毛病的状况的体系。快速失效体系一般规划用于中止正常操作,而不是企图持续或许存在缺点的进程。这种规划一般会在操作中的多个点查看体系的状况,因而能够及早检测就任何毛病。快速失利模块的责任是检测过错,然后让体系的下一个最高级别处理过错。

概念:fail-fast 机制是java调集(Collection)中的一种过错机制。当多个线程对同一个调集的内容进行操作时,就或许会发作fail-fast事情。

二、剖析fail-fast

为了更好的去了解一下fail-fast,咱们先去完成一下这个过错怎么发作。

反常呈现

下面经过一个示例来展现

看一下在Eclipse中处理的成果:

现在咱们fail-fast完成的办法咱们都现已知道了,fail-fast快速失利是在迭代的时分发作的,可是是怎么发作的呢?下面咱们再来深化的剖析一下:

根本原因:

从前面咱们知道fail-fast是在操作迭代器时发作的。现在咱们来看看ArrayList中迭代器的源代码:

从上面的源代码咱们能够看出,迭代器在调用next()、remove()办法时都是调用checkForComodification()办法,它检测modCount == expectedModCount ? 若不等则抛出ConcurrentModificationException 反常,然后发作fail-fast机制。到了这一步咱们也知道了,想要弄清楚fail-fast机制,首要咱们需求搞清楚modCount 和expectedModCount。

expectedModCount 是在IteratorTest中界说的:int expectedModCount = ArrayList.this.modCount;所以他的值是不或许会修正的,所遗嘱-java调集中常见反常fail-fast(面试常问)以会变的便是modCount。modCo遗嘱-java调集中常见反常fail-fast(面试常问)unt是在 AbstractList 中界说的,为全局变量:

protected transient int modCount = 0;

那么他什么时分因为什么原因而发作改动呢?请看ArrayList的源码:

从上面的源代码咱们能够看出,只要是触及了改动ArrayList元素的个数的办法都会导致modCount的改动。所以咱们这儿能够初步判断因为expectedModCount 与modCount的改动不同步,导致两者之间不等,然后发作fail-fast机制。

我想各位现已根本了解了fail-fast的机制,那么往常咱们怎么去躲避这种状况呢?这儿有两种处理计划:

计划一:在遍历进程中一切触及到改动modCount值得当地悉数加上synchronized或许直接运用Collections.synchronizedList(不引荐)

计划二:运用CopyOnWriteArrayList来替换ArrayList。

CopyOnWriteArrayList为什么能处理这个问题呢?CopyOnWrite容器即写时仿制的容器。浅显的了解是当咱们往一个容器增加元素的时分,不直接往当时容器增加,而是先将当时容器进行Copy,仿制出一个新的容器,然后新的容器里增加元素,增加完元素之后,再将原容器的引证指向新的容器。CopyOnWriteArrayList中add/remove等写办法是需求加锁的,意图是为了防止Copy出N个副本出来,导致并发写。可是。CopyOnWriteArrayList中的读办法是没有加锁的。

咱们只需求记住一句话,那便是CopyOnWriteArrayList是雪纳瑞图片线程安全的,所以咱们在多线程的环境下面需求去运用这个就能够了。关于CopyOnWriteArrayList愈加深化的用法,会在今后的章节中去解说阐明。

三、总结

现在咱们对fail-fast机制都现已有了了解了。其呈现的原因是:当多个线程对同一个调集的内容进行操作时,就或许会发作fail-fast事情。类似于咱们在学习操作体系的时分呈现的问题。