publicclassMain{ publicstaticvoidmain(String[] args){ List<Integer> list = new ArrayList<>(); list.add(0); list.add(1); list.add(2);
Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()) list.remove(iterator.next()); } }
If we run the above code it would throw an ConcurrentModificationException. This is because ArrayList is a collection in the java.util, and all collections in java.util are fail-fast. That is, if the collection is modified while using iterator to iterate over it, the iterators would throw an ConcurrentModificationException.
However, if we use a fail-safe collection(i.e. the collections in java.util.concurrent), it would not throw an exception, e.g.
1 2 3 4 5 6 7 8 9 10 11
publicclassMain{ publicstaticvoidmain(String[] args){ List<Integer> list = new CopyOnWriteArrayList<>(); list.add(0); list.add(1); list.add(2);
Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()) list.remove(iterator.next()); } }
Fail-fast Iterator Internal Working
Take ArrayList as an example, let’s walk through why there is an ConcurrentModificationException:
classMyArrayList<E> { // 1. every fail fast collection has a field modCount to store // the times that the collection has been modified int modCount = 0;
// 2. when we call the list.iterator() method, // it will create a new Itr object public Iterator<E> iterator(){ returnnew Itr(); }
privateclassItrimplementsIterator<E> { // 3. initially, the field expectedModCount is equal to modCount int expectedModCount = modCount;
// 4. there is a method checkForComidification method in Itr, // and if the modCount is modified during the iteration, an // ConcurrentModificationException will occur finalvoidcheckForComodification(){ if (modCount != expectedModCount) { thrownew ConcurrentModificationException(); } } }
// 5. the remove operation will definitely modify the modCount, // therefore there is an ConcurrentModificationException publicbooleanremove(Object o){ // Code... } }
classMyCopyOnWriteArrayList<E> { privatevolatile Object[] array; final Object[] getArray() { return array; } // 1. when we call list.iterator(), a COWIterator object is created public Iterator<E> iterator(){ returnnew COWIterator(getArray(), 0); } staticfinalclassCOWIteratorimplementsListIterator<E> { privatefinal Object[] snapshot;// snapshot of MyCopyWriteArrayList.array privateint cursor; // 2. the original collection elements are saved in snapshot, // and the iterator mothods will work on this snapshot privateCOWIterator(Object[] elements, int initialCursor){ snapshot = elements; cursor = initialCursor; } } // 3. therefore, even if there is any change in the original collection, // no exception will be thrown. However, the the iterator will not reflect // the latest state of the collection }