zoukankan      html  css  js  c++  java
  • java.util.ConcurrentModificationException异常分析

    在读阿里Java开发手册时其中集合处理篇

    【强制】 不要在 foreach 循环里进行元素的 remove/add 操作。 remove 元素请使用 Iterator
    方式,如果并发操作,需要对 Iterator 对象加锁。

    正例:

    List<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
      String item = iterator.next();
      if (删除元素的条件) {
        iterator.remove();
      }
    }

    反例:

    for (String item : list) {
      if ("1".equals(item)) {
        list.remove(item);
      }
    } 

    说明: 以上代码的执行结果肯定会出乎大家的意料,那么试一下把“1” 换成“2” ,会是同样的结果吗?

    上面代码正例、反例打印出的结果是一致的,看不出异常,但按照说明把“1”改为“2”,反例报错了,报java.util.ConcurrentModificationException。

    调查了下报异常的原因是:

      源码中每次foreach迭代的时候都有两部操作:

      第一步:iterator.hasNext()  //判断是否有下个元素

    public boolean hasNext() {
        return cursor != size;
    }

      第二步:item = iterator.next()  //将下个元素赋值给item

    public E next() {
           checkForComodification();
           int i = cursor;
           if (i >= size)
                throw new NoSuchElementException();
           Object[] elementData = ArrayList.this.elementData;
           if (i >= elementData.length)
                throw new ConcurrentModificationException();
           cursor = i + 1;
           return (E) elementData[lastRet = i];
    }
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }

    java.util.ConcurrentModificationException由checkForComodification抛出,原因为 modCount != expectedModCount。

    进一步阅读源码,发现:

      1.modCount 时List从new开始,被修改的次数。当List调用Remove等方法时,modCount++

      2.expectedModCount是指Iterator现在期望这个list被修改的次数是多少次。是在Iterator初始化的时候将modCount 的值赋给了expectedModCount

    那么就解释了为什么会报上述异常:

      1.modCount 会随着调用List.remove方法而自动增减,而expectedModCount则不会变化,就导致modCount != expectedModCount。

      2.在删除倒数第二个元素后,cursor=size-1,此时size=size-1,导致hasNext方法认为遍历结束。

    所以在 foreach 循环里进行元素的 remove/add 操作, remove 元素请使用 Iterator。

    Mark!

  • 相关阅读:
    Azure 媒体服务的 RTMP 支持和实时编码器
    在_Linux_中如何使用_gdb_调试_C_程序
    你刚吃的兰州牛肉面,背后就藏着大数据
    《C++覆辙录》——1.9:使用糟糕的语言
    老司机带你用MaxCompute和表格存储玩转车联网数据
    快速部署rabbitMQ教程
    《第一本Docker书(修订版)》——1.3 能用Docker做什么
    《第一本Docker书(修订版)》——第1章_简介_1.1Docker简介
    【DockerCon2017最新技术解读】Docker最新特性介绍
    【DockerCon2017最新技术解读】如何在阿里云一键部署高可用的Kubernetes集群
  • 原文地址:https://www.cnblogs.com/wawadao/p/12760461.html
Copyright © 2011-2022 走看看