zoukankan      html  css  js  c++  java
  • 源码解析- java集合迭代器fail-fast/ fail-safe

    fail-fast 快速失败   fail-safe 安全失败

    说的是在Iterator遍历的过程中,是不能够修改集合数据的,否则就会抛出ConcurrentModificationException。

    看个demo

    执行结果

    看一下我们第35行抛了异常 ConcurrentModificationException

    追一下看看 ArrayList的第850行

    这个方法是通过迭代器获取下一个元素

    checkForComodification();  //问题就在这了,获取之前先进行一次判断

    就是这了,如果判断成立直接抛得ConcurrentModificationException异常

    我们看一下modCount和 expectedModCount分别是啥东西

    modCount是AbstractList的一个属性,

    大概意思就是 当集合的结构发生改变或者size发生变化时,modCount会发生变化

    看一下ArrayList的几个会改变集合结构的方法 remove()  add() 

     

    执行前都会有modCount++操作,也就是说只要集合的结构发生改变,这个modCount就会自增1

    再看一下expectedModCount,

    结了,也就是初始创建迭代器的时候就会expectedModCount = modCount

    也就是说 迭代器在遍历的过程中,每次调用next()方法都会重新校验一下,看看这个modCount变没变,也就是有没有人修改了集合的结构,如果有直接抛异常ConcurrentModificationException

    思考一下为什么不允许迭代器遍历的过程中修改集合结构?

    大概是因为这边在这遍历查着,那边让人改了 会产生很奇怪的结果吧。

    证明一下猜想。首先应从hasNext() next()这两个方法入手, 如何判断下一个元素存在的 

    这是ArrayList内部的迭代器实现,看出两个重要的属性,cursor  size

    看注释也看得出来,cursor就是游标 是迭代器内部的属性 从0开始遍历,

    size是集合整体的大小 是ArrayList的属性,

    hasNext()方法判断的就是当前游标和size

    next()方法会使得游标+1 然后会记录一下最后一次取出元素的位置 lastRet(也就是刚才游标的位置)

    那就证明了,如果我们从外部修改了集合的结构,集合的size会发生变化 但是游标cursor不会改,这不就会有问题了吗

    最后看一下迭代器自带的remove()方法

    先判断下modCount  //确保没人傻了吧唧的从外部修改过集合结构

    执行remove;      //删的是lastRet位置(也就是迭代器最新一次取出来的元素)

    cursor = lastRet;  //游标并没有+1 保持不变

    lastRet = -1;     //最新一次取出来的元素已经被干掉了,给-1

    expectedModCount = modCount;   //重新对一下expectedModCount

    好家伙,不知不觉把迭代器源码就瞅了一遍

    fail-safe

    一般的讲 Java.util包下的集合类都是fail-fast的,因为使用迭代器遍历的时候增删元素不安全

    那么有不安全就有安全的, java.util.cuncurrent并发包下的集合就很安全

    看个demo

    一模一样的操作,换了copyOnWriteArrayList这个集合就可以了,这是为啥呢?   (程序员的病:  为啥不行呢? 为啥又行呢?)

    iterator()  传入  元素数组,0

    看出来了  new 的时候保存了一份当前集合元素快照,

    即使迭代器遍历的过程中集合发生改变也跟我没关系了,我遍历的始终是迭代器保存的快照 over

  • 相关阅读:
    腾讯精选50题算法【二叉搜索树的最近公共祖先】
    潜水一周,我精心整理了两个超级有用的职场生存之道
    全球用尽IPv4的一点思考
    Leetcode算法【114. 二叉树展开为链表】
    【翻译】全新16英寸MacBook Pro评测:开发人员的梦想成真
    Medium高赞系列,如何正确的在Stack Overflow提问
    Typora+PicGo+GitHub实现md自带图床效果
    SpringBoot输出日志到文件
    Mybatis用SQL做自连表查询
    IDEA实用插件推荐及使用方法详解
  • 原文地址:https://www.cnblogs.com/ttaall/p/14629397.html
Copyright © 2011-2022 走看看