栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java集合中快速失败机制详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java集合中快速失败机制详解

前言
  • 以前在看JDK集合源码时,会发现其中有快速失败和失败安全机制的应用实现(以前刚开始看时不知道这个东东是什么意思,后来了解多了才知道这个-_-)
  • 快速失败和失败安全机制其实是一种设计思想,其应用场景不只在Java集合类,很多开源框架里也有提现,Dubbo的集群容错机制,其中除了有快速失败和失败安全机制外,还有失败自动切换、失败自动回复、并行调用多个服务机制。
  • 本人对dubbo框架了解不多,本次只讨论JDK集合内快速失败和失败安全机制的实现。
快速失败机制
  • 首先看一到面试题:
public static void main (String[] args) {
   ArrayList list = new ArrayList<>();
   list.add(1);
   list.add(2);
   for (Integer num : list) {
       if (2 == num) {
           list.remove(num);
       }
   }
   System.out.println(list);
}
  • 此代码执行结果是什么?
  • 很明显这题其实不难,不会打印,直接抛异常:java.util.ConcurrentModificationException

  • 根据异常信息,在ArrayList.java:909行抛异常,点进去看会发现:
final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}
  • 当满足条件modCount != expectedModCount,即会抛出ConcurrentModificationException。
  • 那就看看这两个参数是什么意思。 并且在哪种情况下会满足modCount != expectedModCount。
modCount
  • 看一下modCount字段的备注:

  • 本人英语不好没法整段翻译,着重看图中圈起来的位置说明其fail-fast(快速失败),并且在add和remove方法内对其自增。

  • 上图分别是add方法和remove方法里对modCount的自增操作
expectedModCount
  • 在集合中的一个内部类Itr中,有一个属性expectedModCount,根据字面翻译:预期修改次数

  • 初始化Itr类对象时会第一次赋值:
int expectedModCount = modCount;

  • 在Itr对象里调用remove方法是,会再次进行赋值操作。
modCount != expectedModCount
  • 首先去除Java语法糖机制,看当前类加载后的class文件

  • 在当前foreach循环删除的场景里,foreach最后会被编译成使用Iterator对象。
  • 这里直接调用集合的remove方法,那么会导致modCount,然而Iterator对象里的expectedModCount属性没有更新,所以在使用Iterator对象获取元素时的前置检测不通过,抛出异常:ConcurrentModificationException。
  • 如果使用Iterator对象的remove方法进行删除元素,会对expectedModCount进行赋值操作,以确保modCount == expectedModCount。并发时需要对Iterator对象进行加锁
注:上诉前置检测抛异常原理其实就是快速失败机制的体现,在迭代器访问集合元素时,如果集合内的元素有改动操作,则立即抛出异常。
失败安全机制
  • 和快速失败不同,安全失败是调用过程出现了异常,则是不抛出只记录或打印,然后继续执行后续流程。
  • 在java.util.concurrent的并发集合内都是使用安全失败机制,在遍历集合时不是在原集合上进行遍历,而是直接复制一份原集合内容,在复制的集合内容上进行遍历操作
  • 使用复制原集合内容方式能避免快速失败机制,但是会增加内存占用,并且一致性无法保证,只能保证数据的最终一致性。
  • java.util.concurrent下并发集合可在多线程中并发执行,因为是不会操作原集合内容,所以执行过程中互不影响,都会执行后续流程。
public static void main (String[] args) {
    CopyOnWriteArrayList list = new CopyOnWriteArrayList<>();
    list.add(1);
    list.add(2);
    final Iterator iterator = list.iterator();
    while (iterator.hasNext()) {
        Integer next = iterator.next();
        if (2 == next) {
            list.remove(next);
        }
    }
    System.out.println(list);
}
  • 这里会正常打印结果
最后
  • 如果上述表达有任何问题,欢迎指出!
  • 最后虚心学习,共同进步 -_-
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/358479.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号