近日,在看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