【JAVA】Iterator迭代器的ConcurrentModificationException(并发修改异常)

并发修改异常

  • ConcurrentModificationException
  • 产生原因:
  • 迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致
  • 解决方案:
  • 用for循环遍历,然后用集合对象做对应的操作即可
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

//ConcurrentModificationException: 当不允许这样的修改时,可以通过检测到对象的并发修改的方法来抛出此异常。

public class Main {
    public static void main(String[] args) {
        //Collection<String> s = new ArrayList<>();
        List<String> l = new ArrayList<String>();

        l.add("hello");
        l.add("world");
        l.add("java");
        l.add("java");

        /*
        Iterator<String> it = l.iterator();
        while (it.hasNext()){
            //问题出在这里:进行next时会进行checkForComodification判断,下面add进行modcount++,就会抛出异常
            String s = it.next();
            if (s.equals("world")){
                l.add("javaee");
            }
        }
        System.out.println(l);
        */

        //解决方案:
        for (int i = 0; i < l.size(); i++){
            String s = l.get(i);
            if (s.equals("world")){
                l.add("javaee");
            }
        }
        System.out.println(l);
    }
}

输出结果:

[hello, world, java, java, javaee]

并发修改异常源码分析:
代码中使用了List和ArrayList两个类,这里只对这两个类中用到的源码进行解析:
ArrayList继承了AbstractList抽象类,实现了List接口,ArrayList中的next每执行一次都会检查modCount和expectedModCount两个值是否相等,add每执行一次都会将modCount加一(代码中有标注),在上面Mian的循环中重复执行两个指令会抛出异常。
下面是源码:

public interface List<E>{
    Iterator<E> iterator();
    boolean add(E e);
}

public abstract class AbstractList<E>{
    //modCount定义在父类中
    protected int modCount = 0;
}

public class ArrayList<E> extends AbstractList<E> implements List<E>{

    public boolean add(E e) {
        modCount++;  //这里进行modCount++
        add(e, elementData, size);
        return true;
    }

    public Iterator<E> iterator() {
        return new Itr();
    }

    private class Itr implements Iterator<E> {
        int expectedModCount = modCount;

        //[问题出在这里:每进行一次add方法里面modCount会进行++,但是expectedModcount不会进行++;next中每次都会调用checkForComodification进行判断]
        //modCount:实际修改集合的次数        [这个值来自于ArrayList的父类中]
        //expectedModCount:预期修改集合的次数

        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();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/joker_Ling/article/details/108176959