ConcurrentModificationException异常原因

    在使用迭代器对Vector、ArrayList进行迭代的时候,如果在迭代过程中对其增、删操作,就会抛出java.util.ConcurrentModificationException。

示例:

public class Practice {
    public static void main(String[] args) {
        List<Integer> list=new ArrayList<Integer>();
        list.add(1);
        Iterator<Integer> iterator=list.iterator();

        while (iterator.hasNext()) {
                int i=iterator.next();
                list.remove(i);
        }
    }
}

异常信息:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)

at test.Practice.main(Practice.java:17)

原因分析:
1、代码结构

         ArrayList 继承了 AbstractList,Itr是AbstractList中的内部类,Itr 继承了 Iterator。 

        其中,ArrayList中的iterator();方法继承自AbstractList:

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

        Itr的原码:

private class Itr implements Iterator<E> {
    /**
     * Index of element to be returned by subsequent call to next.
     */
    int cursor = 0;

    /**
     * Index of element returned by most recent call to next or
     * previous.  Reset to -1 if this element is deleted by a call
     * to remove.
     */
    int lastRet = -1;

    /**
     * The modCount value that the iterator believes that the backing
     * List should have.  If this expectation is violated, the iterator
     * has detected concurrent modification.
     */
    int expectedModCount = modCount;

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

    public E next() {
        checkForComodification();
        try {
            int i = cursor;
            E next = get(i);
            lastRet = i;
            cursor = i + 1;
            return next;
        } catch (IndexOutOfBoundsException e) {
            checkForComodification();
            throw new NoSuchElementException();
        }
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            AbstractList.this.remove(lastRet);
            if (lastRet < cursor)
                cursor--;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException e) {
            throw new ConcurrentModificationException();
        }
    }

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

       在Itr中:

       cursor:表示下一个要访问的元素的索引

  lastRet:表示上一个访问的元素的索引

  expectedModCount:ArrayList的预期修改次数,初始值为modCount。

  modCount是AbstractList类中的一个成员变量,为增、删次数。
2、异常原因

    Iterator的next()的实现过程:

public E next() {
    checkForComodification();
    try {
        int i = cursor;
        E next = get(i);
        lastRet = i;
        cursor = i + 1;
        return next;
    } catch (IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
    }
}

在调用Iterator的next()方法时,会调用checkForComodification();

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

在checkForComodification()中,会检查list的实际修改次数(modCount)与内部类Itr的预期修改次数(expectedModCount)是否相等,不相等时,抛出java.util.ConcurrentModificationException。而list中的remove()方法并不会改变expectedModCount,只会改变modCount。

ArrayList中的remove()方法:

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
}

iterator中的remove(),会同步expectedModCount 、modCount;

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        AbstractList.this.remove(lastRet);
        if (lastRet < cursor)
            cursor--;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException e) {
        throw new ConcurrentModificationException();
    }
}
 3、总结

      ArrayList中的迭代器在获取集合中的下个元素时,会用迭代器中保存的集合修改次数和集合本身保存的修改次数进行对比(expectedModCount、modCount),目的在于保证当前迭代集合的完整性。

        使用迭代器Iterator对集合ArrayList进行遍历时,在遍历过程中对集合元素进行增、删操作时,使用迭代器的remove方法,防止出现ConcurrentModificationException。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值