问题:删除Set中的某些元素的时候,使用边遍历,边删除的方法,报以下异常:ConcurrentModificationException
ConcurrentModificationException是Java集合的一个快速失败(fail-fast)机制,防止多个线程同时修改同一个集合的元素。
集合使用迭代器删除元素代码及原理:
private abstract class HashIterator<E> implements Iterator<E> {
Entry<K,V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry<K,V> current; // current entry
HashIterator() {
expectedModCount = modCount;
if (size > 0) { // advance to first entry
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
//调用的这个方法
public void remove() {
if (current == null)
throw new IllegalStateException();
//玄机就在这里:expectedModCount,拷贝网上找来的说明,
/**
*在Iterator的内部有个expectedModCount 变量,
*该变量每次初始化*Iterator的时候等于ArrayList的modCount,modCount记录了对ArrayList的结构修改次数,
*在通过Iterator对ArrayList进行结构的修改的时候都会将expectedModCount 与modCount同步,
*但是如果在通过Iterator访问的时候同时又通过索引的方式去修改ArrayList的结构的话,
*由于通过索引的方式只会修改modCount不会同步修改expectedModCount 就会导致
*modCount和expectedModCount 不相等就会抛ConcurrentModificationException,
*这也就是Iterator的fail-fast,快速失效的。所以只要采取一种方式操作ArrayList就不会出问题,
*当然ArrayList不是线程安全的,此处不讨论对线程问题。
* http://sushe1424.iteye.com/blog/1110796
*/
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Object k = current.key;
current = null;
HashMap.this.removeEntryForKey(k);
expectedModCount = modCount;
}
}
java中对remove方法的介绍:
remove
void remove()从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
每次调用 next 只能调用一次此方法。如果进行迭代时用调用此方法之外的其他方式修改了该
迭代器所指向的 collection,则迭代器的行为是不确定的。
参考:
https://blog.csdn.net/yin_jw/article/details/39668673
https://bbs.csdn.net/topics/390711013
http://sushe1424.iteye.com/blog/1110796