(源码刨析)并发修改异常: java.util.ConcurrentModificationException
Posted 我永远信仰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(源码刨析)并发修改异常: java.util.ConcurrentModificationException相关的知识,希望对你有一定的参考价值。
java.util.ConcurrentModificationException:并发修改异常。
出现的原因是使用迭代器遍历List,在遍历的过程中,对List进行了增删操作。
比如:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if ("world".equals(s)) {//如果两个字符串相等
// list.add("abc"); //抛出异常:ConcurrentModificationException
list.remove(s);//一样抛出异常
}
}
ConcurrentModificationException异常是如何产生的?
查看源码:
//什么情况下会抛出这个异常
final void checkForComodification() {
if (modCount != expectedModCount) //当这两个不相等的时候
throw new ConcurrentModificationException();
}
//这两个又是什么,继续翻源码
private class Itr implements Iterator<E> { //这是实现迭代器接口的类里。我们使用的是迭代器方式遍历
int expectedModCount = modCount; //一个值在这里被定义
/*
modCount:实际修改集合的次数
expectedModCount:预期修改集合的次数
*/
一开始他们是相等的,但是我们上面在上面使用迭代器遍历过程中让它进行了一次add操作,导致这两个值不等,所以抛出了异常。
...
思考:
-
如果if条件不成立,程序仍然会抛出异常吗。
答案是不会,因为if条件不成立,那么if (modCount != expectedModCount) 也成立,就不会抛出异常
-
如果遍历方式改为使用第二种会抛出异常吗
答案是不会,因为get方法只有检测索引的范围是否越界,并没有做checkForComodification()方法。只有索引越界了才会抛出异常:IndexOutOfBoundsException。
-
增强for循环内部也使用了迭代器实现,使用它也可能抛出并发修改异常
总结:
产生原因
-
迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致
-
增强for循环内部也使用了迭代器实现,他也可能抛出并发修改异常
解决方案
- 用for循环遍历,然后用集合对象做对应的操作即可
- 或者使用ListIterator迭代器
ListIterator listIt = list.listIterator();
思考:为什么ListIterator使用add方法,不会抛出并发修改异常?
查看源码
//在调用 list.listIterator()方法的时候,返回的是一个ListItr。
public ListIterator<E> listIterator() {
return new ListItr(0);
}
//找到ListItr,查看ListItr的add方法,
private class ListItr extends Itr implements ListIterator<E> {
...
...
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount; //发现在执行add方法,他也会将这两个值保持一致。所以在检测的时候不会出现异常。
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
总结:
ListIterator使用add方法,不会抛出并发修改异常,因为它会在add方法中执行 expectedModCount = modCount;所以不会抛出并发修改异常
以上是关于(源码刨析)并发修改异常: java.util.ConcurrentModificationException的主要内容,如果未能解决你的问题,请参考以下文章