并发修改异常
- ConcurrentModificationException
- 产生原因:
- 迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致
- 解决方案:
- 用for循环遍历,然后用集合对象做对应的操作即可
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
//ConcurrentModificationException: 当不允许这样的修改时,可以通过检测到对象的并发修改的方法来抛出此异常。
public class Main {
public static void main(String[] args) {
//Collection<String> s = new ArrayList<>();
List<String> l = new ArrayList<String>();
l.add("hello");
l.add("world");
l.add("java");
l.add("java");
/*
Iterator<String> it = l.iterator();
while (it.hasNext()){
//问题出在这里:进行next时会进行checkForComodification判断,下面add进行modcount++,就会抛出异常
String s = it.next();
if (s.equals("world")){
l.add("javaee");
}
}
System.out.println(l);
*/
//解决方案:
for (int i = 0; i < l.size(); i++){
String s = l.get(i);
if (s.equals("world")){
l.add("javaee");
}
}
System.out.println(l);
}
}
输出结果:
[hello, world, java, java, javaee]
并发修改异常源码分析:
代码中使用了List和ArrayList两个类,这里只对这两个类中用到的源码进行解析:
ArrayList继承了AbstractList抽象类,实现了List接口,ArrayList中的next每执行一次都会检查modCount和expectedModCount两个值是否相等,add每执行一次都会将modCount加一(代码中有标注),在上面Mian的循环中重复执行两个指令会抛出异常。
下面是源码:
public interface List<E>{
Iterator<E> iterator();
boolean add(E e);
}
public abstract class AbstractList<E>{
//modCount定义在父类中
protected int modCount = 0;
}
public class ArrayList<E> extends AbstractList<E> implements List<E>{
public boolean add(E e) {
modCount++; //这里进行modCount++
add(e, elementData, size);
return true;
}
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int expectedModCount = modCount;
//[问题出在这里:每进行一次add方法里面modCount会进行++,但是expectedModcount不会进行++;next中每次都会调用checkForComodification进行判断]
//modCount:实际修改集合的次数 [这个值来自于ArrayList的父类中]
//expectedModCount:预期修改集合的次数
public E next() {
checkForComodification();//这里进行检查两个值是否相等
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];
}
//检查两个值是否相等,否则抛出异常
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}