java迭代集合出现并发修改异常(ConcurrentModificationException)的原因以及解决方案
一. 什么时候会出现并发修改异常?
这里先看需求 : 定义一个集合,存储 唐僧,孙悟空,猪八戒,沙僧,遍历集合,如果遍历到猪八戒,往集合中添加一个白龙马
很显然要求我们先创建一个集合并进行迭代 , 当迭代到猪八戒,的时候插入白龙马
代码实现
public static void main(String[] args) {
//需求:定义一个集合,存储 唐僧,孙悟空,猪八戒,沙僧,遍历集合,如果遍历到猪八戒,往集合中添加一个白龙马
ArrayList<String> list = new ArrayList<>();
list.add("唐僧");
list.add("孙悟空");
list.add("猪八戒");
list.add("沙僧");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String element = iterator.next();
if ("猪八戒".equals(element)){
list.add("白龙马");
}
}
System.out.println(list);
}
运行后报错
这里报了一个ConcurrentModificationException 也就是并发修改异常
二. 产生原因
我们来进入源码分析一下
-
首先我们来进入 iterator() 方法 , 这里iterator() 是返回了了一个新对象也就是Itr() , 那我们再来看一下Itr()方法
public Iterator<E> iterator() { return new Itr(); }
-
Itr() , 光观察Itr()好像并没有发现异常的原因 , 那我们再看next()方法
private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; // prevent creating a synthetic constructor Itr() {} public boolean hasNext() { return cursor != size; }
-
next() , 这里在运行next()的时候会先调用checkForComodification();方法那我们就先来查看这个方法
@SuppressWarnings("unchecked") 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]; }
-
checkForComodification() , 很显然这里判断了modCount 与 expectedModCount是否相等 , 如果不相等则抛出throw new ConcurrentModificationException(); 也就是并发修改异常
modCount: 实际操作次数
expectedModCount:预期操作次数final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
-
那么通过上面的分析我们就知道了产生问题的原因是什么 , 也就是modCount 与 expectedModCount并不相等
那是什么导致modCount 与 expectedModCount不相等的呢 ? 在代码中我们调用了一个add方法 , 那么add是否就是产生问题的原因
-
add() , 还是和刚才一样 , 进入add()底层源码我们来找一下原因
public boolean add(E e) { modCount++; add(e, elementData, size); return true; }
到这里就一目了然了我们在调用add的时候会对modCount++ , 在modCount自增之后 , 我们再调用next()方法就会导致modCount 与 expectedModCount不相等 , 从而抛出异常
三. 解决方法
ArrayList中的方法:ListIterator listIterator()
public class Demo03Iterator {
public static void main(String[] args) {
//需求:定义一个集合,存储 唐僧,孙悟空,猪八戒,沙僧,遍历集合,如果遍历到猪八戒,往集合中添加一个白龙马
ArrayList<String> list = new ArrayList<>();
list.add("唐僧");
list.add("孙悟空");
list.add("猪八戒");
list.add("沙僧");
//Iterator<String> iterator = list.iterator();
ListIterator<String> listIterator = list.listIterator();
while(listIterator.hasNext()){
String element = listIterator.next();
if ("猪八戒".equals(element)){
listIterator.add("白龙马");
}
}
System.out.println(list);
}
}