并发修改异常
示例
package com.ningxiao.day18;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Demo02 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("python");
list.add("java");
list.add("C");
list.add("C++");
Iterator<String> it = list.iterator();
while (it.hasNext()){
if (it.next().equals("python")){
list.add(".net");
}
}
}
}
Exception in thread "main"java.util.ConcurrentModificationException
at java.util.ArrayList$ Itr.checkForComodification(ArrayList.java:901)
atjava.util.ArrayList$Itr.next(ArrayList.java:851)atcom.ningxiao.day18.Demo02.main(Demo02.java:21)
分析
过程:
从创建iterator迭代器开始分析:
Iterator<String> it = list.iterator();
现在我们去看底层源码:
public Iterator<E> iterator() {
return new ArrayList.Itr();
}
根据ArrayList内部类Itr创建了一个对象并返回
那我们去看一下这个内部类都有什么内容
private class Itr implements Iterator<E> {
....
int expectedModCount;
Itr() {
this.expectedModCount = ArrayList.this.modCount;
}
}
我们发现他的无参构造方法初始化了一个属性
this.expectedModCount = ArrayList.this.modCount;
那么问题来了,这两个属性是什么?
expectedModCount 是期望修改值
this.modCount 是实际修改值
这两个是什么不重要,重要的是我们知道modCount初始值为0
以上内容说明:
在我们创建一个迭代器的时候,底层源码根据ArrayList内部类Itr帮我们创建了一个迭代器,并且这个迭代器的期望修改值和实际修改值一样
那为什么会报错?
我们看一下抛出的错误源码
final void checkForComodification() {
if (ArrayList.this.modCount != this.expectedModCount) {
throw new ConcurrentModificationException();
}
}
源码说明,当期望修改值与实际修改值不一样的时候报错,
但是在生成迭代器的时候明明两者是相同的,怎么就不一样了?
到底是什么造成了这个错误?
public boolean hasNext() {
return this.cursor != ArrayList.this.size;
}
public E next() {
this.checkForComodification();
int i = this.cursor;
if (i >= ArrayList.this.size) {
throw new NoSuchElementException();
} else {
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
} else {
this.cursor = i + 1;
return elementData[this.lastRet = i];
}
}
}
这两个方法好像也没有修改那两个值
public boolean add(E e) {
++this.modCount;
this.add(e, this.elementData, this.size);
return true;
}
add()方法修改了modCount值,原因就在这里,modCount改变
而expectedModCount没有发生变化,就造成了两者不一样,因此
在代码执行next()的时候
public E next() {
this.checkForComodification();
int i = this.cursor;
if (i >= ArrayList.this.size) {
throw new NoSuchElementException();
} else {
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
} else {
this.cursor = i + 1;
return elementData[this.lastRet = i];
}
}
}
第一行就检查两者是否相等,因为两者不相等,就抛出了异常
解决的方案
不使用迭代器,用for循环遍历,然后用集合对象做对应的操作即可。