先看怎麼發生java
List<Integer> list=new ArrayList<>(); for(int i=0;i<10;i++){ list.add(i); } Iterator<Integer> it=list.iterator(); while(it.hasNext()){ Integer str=it.next(); if(str==5) list.remove(str);//不經過it.remove()方法刪除,而是經過list.remove()方法刪除元素 }
這段代碼,就會發生java.util.ConcurrentModificationException異常
一下看看實現:
先看 AbstractList 類有這樣一個變量安全
/** * The number of times this list has been <i>structurally modified</i>. * Structural modifications are those that change the size of the * list, or otherwise perturb it in such a fashion that iterations in * progress may yield incorrect results. * 他表明list被修改的次數(通常指 add,remove 次數。某個元素重賦值,通常不計數 ) * <p>This field is used by the iterator and list iterator implementation * returned by the {@code iterator} and {@code listIterator} methods. * If the value of this field changes unexpectedly, the iterator (or list * iterator) will throw a {@code ConcurrentModificationException} in * response to the {@code next}, {@code remove}, {@code previous}, * {@code set} or {@code add} operations. This provides * <i>fail-fast</i> behavior, rather than non-deterministic behavior in * the face of concurrent modification during iteration. * 這個變量,通常在是 iterator , list iterator 實現時用到的,而且在他們的 next,remove,add,previous 等方法中,會利用它決定是否拋出ConcurrentModificationException異常。 * <p><b>Use of this field by subclasses is optional.</b> If a subclass * wishes to provide fail-fast iterators (and list iterators), then it * merely has to increment this field in its {@code add(int, E)} and * {@code remove(int)} methods (and any other methods that it overrides * that result in structural modifications to the list). A single call to * {@code add(int, E)} or {@code remove(int)} must add no more than * one to this field, or the iterators (and list iterators) will throw * bogus {@code ConcurrentModificationExceptions}. If an implementation * does not wish to provide fail-fast iterators, this field may be * ignored. * 也能夠在子類中利用這個字段,提供快速失敗機制。具體在像add,remove方法中,增長modCount的值,每次調用加1。而後利用它,決定是否拋出ConcurrentModificationExceptions */ protected transient int modCount = 0;
接着看ArrayList類方法多線程
/** * Returns an iterator over the elements in this list in proper sequence. * 這個方法,返回一個自己list的一個iterator * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * * @return an iterator over the elements in this list in proper sequence */ public Iterator<E> iterator() { return new Itr();//關鍵這個類 }
再看 Itr類ide
/** * An optimized version of AbstractList.Itr */ private class Itr implements Iterator<E> { int cursor; // index of next element to return //有個潛臺詞,默認值是0,list當前的下標 int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount;//初始化時候,會把list原來的修改次數,賦給expectedModCount public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification();//會拋出java.util.ConcurrentModificationException異常 int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1;//每次,移動下標加1,下次的遊標位置 return (E) elementData[lastRet = i];//lastRet 賦值本次的座標。 } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification();//會拋出java.util.ConcurrentModificationException異常 try { ArrayList.this.remove(lastRet);//根據下標刪除元素,ArrayList.this.remove()方法,會modCount++; cursor = lastRet; lastRet = -1; expectedModCount = modCount;//讓後又把最新的modCount 賦給expectedModCount,這樣保證,經過Itr remove方法刪除元素,不會拋ConcurrentModificationException異常,由於expectedModCount == modCount } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } final void checkForComodification() {//拋出java.util.ConcurrentModificationException異常的方法 if (modCount != expectedModCount)//若是modCount 不等於expectedModCount 就拋出這個異常 throw new ConcurrentModificationException(); } }
最後,再回來講ConcurrentModificationException異常,直接一點,它的做用是,一個集合(list 實現,好比ArrayList,LinkedList,Vertor 等AbstractList子類),
在用它本身的Iterator對象 在玩轉它自己時(next,remove,add,previous 調用)時,若是發現有其餘方式(非這個Iterator 對象),
修改這個list對象,就會(經過比較modCount, expectedModCount值)拋出ConcurrentModificationException異常。因爲 Iterator 對象不是線程安全的,在多線程中用it.remove()刪除元素,一樣能夠拋出 ConcurrentModificationException異常 !this