ArrayList什么状况会抛出ConcurrentModificationException

近日,在看ArrayList的源码实现。发现不少状况会抛出ConcurrentModificationException。下面总结一下大体发生的状况。 首先,ArrayList不是线程安全的。 首先来看一个例子:java

public  static  void main(String[] args){
        List<Integer> aList = new ArrayList<Integer>();
        aList.add(1);
        aList.add(2);

        Iterator<Integer> iter = aList.iterator();
        aList.add(3);
        System.out.println(iter.next());
    }

运行结果:数组

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
	at java.util.ArrayList$Itr.next(ArrayList.java:831)
	at com.zhu.util.ArrayIistIteratorTest.main(ArrayIistIteratorTest.java:19)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

由例子可见,在调用iterator方法后,若是其余线程对ArrayList进行了更改大小的操做,如add和remove。那么将会抛出ConcurrentModificationException。字面意思很简单:并发修改异常。安全

咱们经过源码,来看看为何会出现这样的状况: 首先ArrayList的iterator方法实现:并发

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

Itr是ArrayList的内部类,实现了Iterator<E>接口,下面是Itr的源码:app

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,exceptdModCountthis

  • cursor:next方法应该返回元素所在的下标
  • lastRet:上一次next返回元素的下标
  • exceptedModCount:ArrayList成员变量modCount的副本 ArrayList中modCount的意义是记录当前ArrayList被修改的次数,ArrayList中会引发modCount发生改变的方法有如下集中:
    1. trimToSize:将数组大小减少至当前元素个数
    2. ensureCapacity:容量设置
    3. add:新增元素的时候
    4. remove:移除元素的时候
    5. clear:清空的时候 全部移除和新增的操做都会引发modCount的修改

能够看出引发例子抛出异常的缘由是由于Itr建立以后,exceptedModCount为当时ArrayList对象modCount的值。在Itr的next和remove方法中能够看出,在世纪操做以前都会调用checkForComodification来检查ArrayList是否被修改过。在调用Itr中next和remove与Itr建立之间,若是有其余线程或本线程调用了引发ArrayList的modCount发生变化的操做,那么将会抛出并发修改异常。线程

那么下面咱们再来看看还有其余什么状况,ArrayList会抛出CurrentModificationException。code

  1. writeObject:writeObject是序列化时调用的方法,也就是说在在元素序列化时,若是有其余操做引发了modCount发生改变时会抛出并发修改异常。
  2. Itr的next和remove:在使用迭代器期间,其余操做引发modCount改变时。
  3. ListItr的previous,next,set,remove,add:同Itr.
  4. SubList中的全部操做
相关文章
相关标签/搜索