0 results found
liang
Java的fail-fast与fail-safe机制
2019/12/17 Java 集合
  1. fail-fast(快速失败)
    fail-fast是Java集合的一种错误检测机制,若一个方法不允许集合被多个线程同时修改,当方法检测到集合对象的并发修改时,就会抛出ConcurrentModificationException异常。
    java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。
    用List来举例:
List<String> list = new ArrayList<>();
list.add("0");
list.add("1");
list.add("2");
list.add("3");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
    String next = iterator.next();
    System.out.println(next);
    if (next.equals("1")){
        list.remove(next);
    }
}

运行结果:


点开ArrayList的源码可以看到checkForComodification()这个方法


这个方法是异常抛出的地方


这个方法内容也很简单,就是比较modCount和expectedModCount这两个值


所以我们要搞清楚,到底modCount和expectedModCount这两个变量都是什么东西。

通过翻源码,我们可以发现:

这段话的意思是modCount表示List的结构被修改的次数,结构修改是指List的大小被修改,即新增和删除操作,会改变modCount的值。modCount被迭代器使用,如果这个值被意外改变,就会抛出ConcurrentModificationException。


而expectedModCount 是 ArrayList中的一个内部类——Itr中的成员变量,其值的初始值即是modCount。



当List进行删除操作时,modCount+1,而expectedModCount却还是原先的值,所以当迭代器执行next方法时就会检测到集合的结构被改变了,所以就会抛出ConcurrentModificationException异常。

这也是为什么在阿里巴巴Java开发手册中,关于集合操作有这样一条强制规定:

foreach 循环实际上是一个语法糖, foreach 对集合的遍历也是使用iterator迭代器迭代,所以当迭代器每一次迭代都会检查modCount和expectedModCount是否相等,所以在foreach循环中进行add/remove操作也会抛出ConcurrentModificationException异常。

  1. fail-safe(安全失败)
    在并发包下的容器是采用fail-sale机制,它在遍历时不是直接在原集合内容上遍历的,而是先复制集合内容,在集合的拷贝上进行遍历,这样的遍历,由于在遍历过程中,集合的修改不会被迭代器检测到,也会不会抛出异常。
    基于拷贝内容的优点是避免了ConcurrentModificationException,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

例如 java.util.concurrent.ConcurrentLinkedDeque;

ConcurrentLinkedDeque<String> concurrentLinkedDeque = new ConcurrentLinkedDeque<>();
        concurrentLinkedDeque.add("1");
        concurrentLinkedDeque.add("2");
        concurrentLinkedDeque.add("3");
        concurrentLinkedDeque.add("4");

        for (String num:concurrentLinkedDeque){
            concurrentLinkedDeque.remove();
            System.out.println("num:"+num);
            System.out.println("size:"+concurrentLinkedDeque.size());
        }

运行结果:

打赏
支付宝
微信
本文作者:liang
版权声明:本文首发于liang的博客,转载请注明出处!