ConcurrentModificationException原因分析

编程技术  /  houtizong 发布于 3年前   82
package com.ljn.base;import java.util.ArrayList;import java.util.Iterator;import java.util.List;/** *  “对ArrayList进行遍历时,不要进行list.remove或者list.add操作” *  我只是记住了这条规则,但规则的背后,是什么原理? *  通过代码来说明(暂时不考虑多线程的情况): */public class ConcurrentModificationExceptionTest {    public static void main(String[] args) {        remove(newArrayList(), "b");        remove(newArrayList(), "a");    }    private static void remove(List<String> list, String itemToRemove) {        Iterator<String> iterator = list.iterator();        int i = 1;        while (iterator.hasNext()) {            String item = iterator.next();            System.out.println(i++);            if (item.equals(itemToRemove)) {                list.remove(item);                System.out.println(item + " is removed");            } else {                System.out.println(item);            }        }        System.out.println();    }        private static List<String> newArrayList() {        List<String> list = new ArrayList<String>();        list.add("a");        list.add("b");        list.add("c");        return list;    }        /*很简单的程序,输出如下:1a2b is removed1a is removedException in thread "main" java.util.ConcurrentModificationException    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)    at java.util.AbstractList$Itr.next(AbstractList.java:343)为什么remove(newArrayList(), "a")会抛异常,而remove(newArrayList(), "b")就不会?AbstractList里面有一个字段modCount,用来记录List“结构性改变”的次数,执行add或者remove都会使得modCount加1AbstractList.iterator会创建一个AbstractList.Itr(内部类),而Itr备份了modCount,命名为expectedModCountItr执行next和remove操作前,都会调用checkForComodification方法检查expectedModCount是否等于modCount,如果不等,就报ConcurrentModificationException同时注意到Itr有一个指针cursor,表示下一个要遍历的元素的下标,初始值为0Itr调用hasNext时,会将cursor与数组大小比较:public boolean hasNext() {            return cursor != size();}回到例子先看remove(newArrayList(), "a"):1.newArrayList()之后,modCount=32.list.iterator()之后,Itr的expectedModCount=modCount=33.调用hasNext(),next(),再调用list.remove(item),此时modCount=44.调用hasNext(),next(),在next里面进行检查,发现expectedModCount不等于modCount,于是报错再看remove(newArrayList(), "b"):1.newArrayList()之后,modCount=3, list.size=32.list.iterator()之后,Itr的expectedModCount=modCount=3,cursor=03.调用hasNext(),next(),打印a,list.size=2,cursor=1;没有对list做修改,因此expectedModCount=34.调用hasNext(),next(),检查expectedModCount和modCount,都等于3,因此检查通过,b is removed;此时cursor=2,size=25.调用hasNext,此时cursor 与 size()都等于2,hasNext返回false,循环结束由此可见,remove(newArrayList(), "b")只是侥幸地成功运行了,但仍然是错误的用法*/    }

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客