jdk文档中关于 ConcurrentModificationException的描述为:
当不允许这样的修改时,可以通过检测到对象的并发修改的方法来抛出此异常。
出现的原因
迭代器遍历的过程中,通过集合对象修改了集合中的元素,造成了迭代器获取元素中判断预期修改值和实际修改值不一致,则会出现:ConcurrentModificationException
示例代码:
package com.me.list.test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ConcurrentModification {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
//如果有”bbb“这个元素,添加一个”abc“
if (s.equals("bbb")) {
list.add("abc");
}
}
System.out.println(list);
}
}
错误显示信息
原因分析:
根据追踪源码发现,并发修改异常是因为在操作集合时,增删操作会导致预期修改集合次数和实际修改集合次数不一致(一开始,他们是一致的),所以就抛出了并发修改异常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
public interface List<E> extends Collection<E> {
Iterator<E> iterator();
boolean add(E e);
}
public abstract class AbstractList<E> {
protected int modCount = 0; //a1
}
public class ArrayList<E> extends AbstractList<E> implements List<E>{
public E get(int index) {
//根据索引获取元素
rangeCheck(index);
return elementData(index);
}
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!a3调用add方法后modCount
elementData[size++] = e;
return true;
}
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int expectedModCount = modCount;//一开始两个都是0 a2
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() {
//modCount实际修改集合的次数
//expectedModCount预期修改集合的次数
if (modCount != expectedModCount)//a4此时if的结果为false
throw new ConcurrentModificationException();
}
}
解决方法:
1.使用for循环遍历
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);//因为get方法中没有改变modCount与expectedModCount的值
if (s.equals("bbb")) {
list.add("abc");
}
}
2.list集合有一个ListIterator的迭代器可以对元素进行添加
原因是在listiterator中调用add()方法时,会将实际修改集合的次数赋值给预期修改集合的次数,也就是让它们两个始终相等。
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}