快速失败“fail-fast”和安全失败“fail-safe”

目录

快速失败——fail-fast

异常原因

 正常原因

 安全失败“fail-safe”


快速失败——fail-fast

java的快速失败机制是java集合框架中的一种错误检测机制,当多个线程对集合中的内容进行修改时可能就会抛出ConcurrentModificationException异常。不仅仅在多线程状态下,在单线程中使用增强for循环一边遍历集合一边修改集合的元素也会抛出ConcurrentModificationException异常。例如:

public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("java");
        list.add("python");
        list.add("c++");
        for (String s:list){
            list.remove(s);
        }
    }
}

抛出异常:

 正确做法使用迭代器的remove()方法,可正常删除

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("java");
        list.add("python");
        list.add("c++");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            iterator.next();//获取下一个元素
            iterator.remove();//删除当前元素
        }
    }

异常原因

首先查看list.remove()源码:

根据值找到对应的索引后调用fastRemove(index)方法 ,查看fastRemove(int index)方法

 发现第一个元素可以正常删除,但由于使用for-each循环,底层实际使用的是迭代器遍历当执行for (String s : list)时,Java会隐式地创建一个迭代器,并调用iterator()方法开始迭代。迭代过程:在每次循环中,Java会调用迭代器的next()方法获取下一个元素,并将其赋值给s。删除元素:然后执行list.remove(s),这实际上调用了remove()方法,删除了当前引用的元素。

 在调用next()时,里面包含checkForComodification();方法,该方法将modCount和expectedModCount进行比较。

checkForComodification()源码:

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

因此抛出了 ConcurrentModificationException异常。

 正常原因

由于迭代器使用的remove()和上面的remove()方法不同,源码:

 迭代器的remove()方法保证了expectedModCount = modCount;因此也保证了不会出现ConcurrentModificationException异常。

虽然在线程下,使用迭代器可以避免ConcurrentModificationException异常,但是在多线程下,使用迭代器的remove()方法还会报异常。

        这是因为modCount是在AbstractList类中定义的,而expectedModCount是在ArrayList内部类中定义,所以modCount是一个共享变量,而expectedModCount是属于线程各自的。

例如:当线程1更新了modCount属于自己的expectedModCount,而线程2只有看到modCount更新,自己的expectedModCount并没有更新,因此抛出ConcurrentModificationException异常。

 例如:

  1. ArrayList
  2. Vector
  3. HashMap
  4. HashSet
  5. LinkedHashMap
  6. LinkedHashSet

实现了"fail-fast"机制。

 安全失败“fail-safe”

在遍历集合时,不是直接在集合内容上进行访问,而是先复制原有集合内容,在复制的集合上进行遍历,在遍历时,对集合的修改是不会被迭代器检测到,所以不会抛出ConcurrentModificationException异常。

缺点:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间,原集合发生了修改,迭代器是无法访问到的。

在java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用:

例如:

  1. CopyOnWriteArrayList、
  2. CopyOnWriteArraySet
  3. ConcurrentHashMap
  • 28
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小俱的一步步

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值