博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ConcurrentModificationException异常原因及解决方法
阅读量:2304 次
发布时间:2019-05-09

本文共 3590 字,大约阅读时间需要 11 分钟。

冲天香阵透长安,满城尽带黄金甲

上次在写代码时,使用迭代器遍历一个集合,并在迭代中移除(或下新增)集合中的某项,就会出现ConcurrentModificationException异常。

问题复现

问题代码

public static void main(String[] args) {
//定义一个集合 List
list = new ArrayList<>(); //给集合添加数据 list.add("a"); list.add("b"); list.add("c"); //迭代集合 Iterator
iterator = list.iterator(); while(iterator.hasNext()) {
//拿到集合中的下一个值 String next = iterator.next(); System.out.println(next); //移除集合中索引为1的数据 list.remove(1); } }

异常信息

Exception in thread "main" java.util.ConcurrentModificationException	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)	at java.util.ArrayList$Itr.next(ArrayList.java:831)

原因分析

从异常信息中可以看出,是由next方法调用checkForComodification方法抛出的异常,接着我们找到ArrayList子类Itr下的next和checkForComodification方法,如下:

private class Itr implements Iterator
{
int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() {
return cursor != size; } @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]; } public void remove() {
if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try {
ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException(); } } final void checkForComodification() {
if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }

可以看到,在调用next方式,会先调用checkForComodification方法判断集合修改的次数和预期的值是否一致,不一致则会抛出ConcurrentModificationException异常。由控制台打印的信息可以看出,modCount != expectedModCount,即抛出了该异常。

那么,为什么modCount != expectedModCount,说明这个问题,我们接着看remove方法:

public E remove(int index) {
rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }

可以看到,在remove方法中,执行了modCount++;,使得modCount的值加了1,而expectedModCount并没有变化,所以在remove之后,调用next时,next方法又调用checkForComodification判断方法,此时,modCount != expectedModCount,就抛出了异常。

问题解决

解决这个问题也很简单,将代码中的//移除集合中索引为1的数据 list.remove(1);改为迭代器的remove方法即可,即:iterator.remove();。我们来看看迭代器的remove方法实现:

public void remove() {
if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try {
ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException(); }}

方法里面有expectedModCount = modCount;赋值操作,所以,在checkForComodification判断时就不会出异常了。

转载地址:http://ywiib.baihongyu.com/

你可能感兴趣的文章
NSArray数组(2)
查看>>
NSDictionary 字典类
查看>>
NSSet 集合
查看>>
集合之间相互转换
查看>>
集合的内存管理
查看>>
文件操作
查看>>
NSData
查看>>
日期操作
查看>>
iOS的三种弹框
查看>>
UIApplication和程序启动过程
查看>>
cocoaPods安装2017 以及遇到的坑
查看>>
Android中自定义可以选择中文的NumberPicker屏蔽弹出软键盘
查看>>
Scrapy教程——搭建环境、创建项目、爬取内容、保存文件(txt)
查看>>
SQL SERVER 2012 附加数据AdventureWorks2012失败解决方案
查看>>
C++内联函数(inline)的工作原理与例子
查看>>
Eclipse中使用svn主要命令的详细介绍
查看>>
MS第二题解题思路
查看>>
第一个mpi程序in linux
查看>>
epoll 详解
查看>>
Hadoop 面试题
查看>>