近日,在看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
能够看出引发例子抛出异常的缘由是由于Itr建立以后,exceptedModCount为当时ArrayList对象modCount的值。在Itr的next和remove方法中能够看出,在世纪操做以前都会调用checkForComodification来检查ArrayList是否被修改过。在调用Itr中next和remove与Itr建立之间,若是有其余线程或本线程调用了引发ArrayList的modCount发生变化的操做,那么将会抛出并发修改异常。线程
那么下面咱们再来看看还有其余什么状况,ArrayList会抛出CurrentModificationException。code