• List remove ConcurrentModificationException源码分析



    代码块
    Java
     
     
     
     
    Exception in thread "main" java.util.ConcurrentModificationException
      at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
      at java.util.ArrayList$Itr.next(ArrayList.java:859)
      at com.mashibing.tank.Test2.main(Test2.java:14)
     

    ArrayList在迭代删除元素时,如果使用不当会发生concurrentModification 异常,常见的错误使用场景

     

    代码块
    Java
     
     
     
     
    Iterator<Integer> iterator = list.iterator();
    while(iterator.hasNext()){
        Integer next = iterator.next();
            list.remove(next);
    }
     
    代码块
    Java
     
     
     
     
    for (Integer next:list
         ) {
        list.remove(next);
    }
     

    发生异常原因:

    首先明确以上两种方式是等效的,原因:增强for在反编译后语句

    代码块
    Java
     
     
     
     
    Iterator var4 = var1.iterator();
    while(var4.hasNext()) {
        Integer var3 = (Integer)var4.next();
        var1.remove(var3);
    }
     

     

    然后我们去分析发生concurrentModification原因:

    由于异常发生在 :java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909),我们先去看下此处代码

    发现remove(intxOrObject) 方法为 ArrayList 内部类Itr的一个方法 ,当modCount != expectedModCount 时会抛出异常ConcurrentModificationException。

    先来解释下概念:

    modCount:为 成员变量 list 被修改的次数 ,每次add ,remove都会+1 (The number of times this list has been )

    代码块
    Java
     
     
     
     
    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>
          //The number of times this list has been
          protected transient int modCount = 0;
     

    expectedModCount:为listIterator 方法 局部变量,表示对ArrayList修改次数的期望值,它的初始值为modCount

     

    代码块
    Java
     
     
     
     
     
    public Iterator<E> iterator() {
        return listIterator();
    }
    public ListIterator<E> listIterator(final int index) {
        checkForComodification();
        rangeCheckForAdd(index);
        final int offset = this.offset;
        return new ListIterator<E>() {
            int cursor = index;
            int lastRet = -1;
            //注意这里
            int expectedModCount = ArrayList.this.modCount;
            .......
            }
            ....
          }
          .....
      }
     
    代码块
    Java
     
     
     
     
     
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;
        Itr() {}
        public boolean hasNext() {
            return cursor != size;
        }
        @SuppressWarnings("unchecked")
        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];
        }
    }
     

    这里假设原始list 长度为10(只做过新增,没有做过删除操作) 。

    这时候最初 AbstractList.modCount =10 ;

    Iterator.expectedModCount = modCount =10 ;

    1.当第一次循环调用next时,无变动list ,所以expectedModCount = modCount =10 ,

    2.当 arrayList.remove(indexOrObject)时,modCount++ 变为11 ,expectedModCount 依然为10 。

    3.第二次调用next 时,Itr 会执行checkForComodification() ,也就是判断expectedModCount、 modCount 是否一致,如果不一致则抛出ConcurrentModificationException 。

    正确姿势:

    关注点:

    1.增强for循环不要删除元素

    2.使用Iterator<Integer> iterator = list.iterator(); 方式时,先获取元素,然后使用iterator.remove() 进行删除

    代码块
    Java
     
     
     
     
    Iterator<Integer> iterator = list.iterator();
    while (iterator.hasNext() ) {
        System.out.println(iterator.next());
        iterator.remove();
    }
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
        list.remove(i);
    }
     

    为什么Iterator<Integer> iterator = list.iterator(); 方式时 用iterator remove 不会出现问题?看源码:

    代码块
    Java
     
     
     
     
    private class Itr implements Iterator<E> {
        public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();
        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            //关注这里, Itr里将modCount 赋值给expectedModCount 
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
        }
     

    为什么普通循环不会有ConcurrentModificationException ,看源码:

    代码块
    Java
     
     
     
     
    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        public boolean remove(Object o) {
            if (o == null) {
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {
                        fastRemove(index);
                        return true;
                    }
            }
            return false;
        }
        private void fastRemove(int index) {
            modCount++;
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved);
            elementData[--size] = null; // clear to let GC do its work
        }
    }
     
  • 相关阅读:
    Gin编写图床后端上传图片代码实现
    Kubernetes的ETCD集群备份、恢复
    Linux虚拟机(lvm)报Unmount and run xfs_repair
    Pod长时处于init状态
    netstat命令查看网络连接各状态的连接数
    WARNING: HiveonMR is deprecated in Hive 2 and may not be available in the future versions. Consider using a different execution engine (i.e. spark, tez) or using Hive 1.X releases.
    启动azkaban服务加载不到钉钉报警机器人的插件
    Mac系统查看maven版本时出现The JAVA_HOME environment variable is not defined correctly, this environment variable is needed to run this program.
    Plugin 'mavenassemblyplugin:' not found
    钉钉机器人发送消息出现{"errcode":310000,"errmsg":"keywords not in content
  • 原文地址:https://www.cnblogs.com/yueyazhishang/p/12462221.html
Copyright © 2020-2023  润新知