欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ConcurrentModificationException异常

程序员文章站 2022-04-18 17:18:50
...

ConcurrentModificationException异常
也叫作并发修改异常
如下:

 ArrayList<String> list = new ArrayList<>();
        list.add("111");
        list.add("222");
        list.add("333");


        System.out.println(list);
        //遍历
        //ConcurrentModificationException 并发(同时  两个以上同时)修改异常
        //操作元素时保证只有一个对象在操作
       Iterator<String> it =  list.iterator();
       while (it.hasNext()){
           String i = (String) it.next();
           System.out.println(i);

           if (i.equals("222")){
               list.remove("222"); //倒数第二个 源码 校验机制(size() -1 ! = 0)=> 执行校验机制
              // it.remove();  //不会出现异常
           }
       }
        System.out.println(list);
        

当运行上述代码时,程序抛出了ConcurrentModificationException异常。
ConcurrentModificationException异常与modCount这个变量有关

modCount的作用。
modCount就是修改次数,在具体的实现类中的Iterator中才会使用。在List集合中,ArrayList是List接口的实现类。

modCount:表示list集合结构上被修改的次数。(在ArrayList所有涉及结构变化的方法中,都增加了modCount的值)

list结构上被修改指的是:改变了list的长度的大小或者是遍历结果中产生了不正确的结果的方式。add()和remove()方法会是的modCount进行+1操作。modCount被修改后会产生ConcurrentModificationException异常, 这是jdk的快速失败原则。

modCount被定义在ArrayList的父类AbstractList中,初值为0,protected transient int modCount = 0。

在进行add()方法是,先调用的ensureCapacity()这个方法,来判断是否需要扩容

在判断是否需要扩容时,用调用ensureExplicitCapacity这个方法,注意,这个方法中对modCount进行的加一操作。所以集合在进行添加元素是会对modCount进行+1的操作。

在进行文章开头的代码时list集合中使用add添加了元素后,size=3,modCount=3。

Iterator的方法是返回了一个Itr()的类的一个实例。

在for循环内部首先对Iterator进行了初始化,初始化。expectedModCount=3,cursor=0。

hasNext是判断是否有下一个元素,判断条件是cursor不等于size,有下一个元素。size=3,cursor=0,是有下一个元素的。

当进行next()方法时,调用了checkForComodification()方法,进行判断是否抛出异常
可以看见进行remove操作时,是通过调用fastRemove()方法进行的实际删除。在fastRemove()方法中,对modCount进行了+1的操作。

此时,modCount=expectedModCount=3,不抛异常,程序继续进行,next()方法有对cursor进行了加一的操作。cursor=1。e=“222”。此时进行remove删除操作。

ArrayList中remove实际在调用fastRemove()方法进行实际的删除,modCount进行了+1操作,modCount=4,size进行了-1的操作,size=2,程序继续进行,cursor=1,size=2,进行next()方法,发现modCount不等于expectedModCount,抛出了ConcurrentModificationException异常。

解决方法:
使用Iterator提供的remove方法,用于删除当前元素。
建立一个集合,记录需要删除的元素,之后统一删除。
不使用Iterator进行遍历,需要注意的是得保证索引正常
使用并发集合类来避免ConcurrentModificationException,比如使用CopyOnArrayList,而不是ArrayList