我们先来看一段简单的代码:
public class VectorFor {
public static void test1(Vector<Integer> vector){
for (Integer i: vector) {
if(i.equals(3)){
vector.remove(i);
}
}
}
public static void main(String[] args) {
Vector<Integer> vector=new Vector();
vector.add(1);
vector.add(2);
vector.add(3);
test1(vector);
}
}
看上去没什么不妥,就是遍历删除指定元素嘛,运行呢?
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.Vector$Itr.checkForComodification(Vector.java:1184)
at java.util.Vector$Itr.next(Vector.java:1137)
at com.example.demo.plaintest.VectorFor.test1(VectorFor.java:7)
at com.example.demo.plaintest.VectorFor.main(VectorFor.java:18)
Process finished with exit code 1
抛出了一个ConcurrentModificationException
异常
哪里抛出来的呢?
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
哪里调的这个方法呢?
public E next() {
synchronized (Vector.this) {
checkForComodification();
int i = cursor;
if (i >= elementCount)
throw new NoSuchElementException();
cursor = i + 1;
return elementData(lastRet = i);
}
}
那么表面原因很简单,就是modCount != expectedModCount
,这里foreach循环其实还是用的迭代器,我这里调用的remove方法,这个方法里肯定有修改modcount
的地方,去看看
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
一直追踪下去都没有看见更新expectedModCount
的操作,所以呢到后面check的时候就指定会报错了
那么为什么会有它呢?参考了一下别的文章给出了解释
这个和多线程并发修改相关,先介绍一下fail-fast
机制:
“快速失败”也就是fail-fast,它是Java集合的一种错误检测机制。当多个线程对集合进行结构上的改变的操作时,有可能会产生fail-fast机制。记住是有可能,而不是一定。例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生fail-fast机制。
之所以有modCount这个成员变量,就是为了辨别多线程修改集合时出现的错误。
在单线程的环境下也可能会发生该异常
网友评论