Iterator接口中的主要方法:
public interface Iterator<E> {
boolean hasNext();//判断是否有下一个元素
E next();//获取下一个元素
default void remove() {//删除元素
throw new UnsupportedOperationException("remove");
}
ArrayList中的实现:
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; //下一个元素的索引
int lastRet = -1; // 最后一个元素的索引
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;//当下一个元素的索引等于数组中元素个数时返回false
}
public E next() {
checkForComodification();//fast-fail机制,后续说明
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;//复制一个新的数组,减少一次寻址
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);//调用ArrayList中的remove方法
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;//重置expectedModCount,避免fast-fail
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
//Itr类只实现了remove(),ListItr类则实现了add(),set(),hasPrevious()和previous()方法,可以实现逆向遍历
fast-fail机制 fail-fast机制是一种错误检测机制。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。在运行下面的代码时会报 java.util.ConcurrentModificationException
ArrayList<Integer> a = new ArrayList<>();
for(int i=0;i<5;i++){
a.add(i);
}
Iterator<Integer> it = a.iterator();
while(it.hasNext()){
if(it.next() == 2){
a.remove(2);
}
}
分析原因:
ArrayList.Itr:
int expectedModCount = modCount;
remove方法中:
modCount++;
此时expectedModCount != modCount
在next方法中首先调用了checkForComodification()
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
此时抛出异常。而在Iterator.remove()中重置了expectedModCount,不会抛异常。
当多个线程对同一个集合进行操作的时候,某线程访问集合时,集合的内容被其他线程所改变(即改变了modCount),这时会抛出ConcurrentModificationException异常。