使用迭代器遍历List的时候修改List报ConcurrentModificationException异常原因分析
在使用Iterator来迭代遍历List的时候如果修改该List对象,则会报java.util.ConcurrentModificationException异常,下面看一个例子演示:
package com.others; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; public class ArrayListTest { public static void main(String[] args) {
List<String> list = new ArrayList<String>();
//CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
Iterator iterator = list.iterator();
while(iterator.hasNext()){
String str = (String) iterator.next();
if(str.equals("c")){
list.remove(str);
}else{
System.out.println(str);
}
}
} }
结果为:
a
b
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at com.others.ArrayListTest.main(ArrayListTest.java:20)
当调用list的iterator()方法的时候,返回的是一个Itr对象(实现了Iterator接口):
public Iterator<E> iterator() {
return new Itr();
}
我们看一下Itr这个类:
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; //刚创建迭代对象的时候List的modCount public boolean hasNext() {
return cursor != size;
} @SuppressWarnings("unchecked")
public E next() {
checkForComodification(); //每调用一次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();
}
}
//此方法用来判断创建迭代对象的时候List的modCount与现在List的modCount是否一样,不一样的话就报ConcurrentModificationException异常
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
List对象有一个成员变量modCount,它代表该List对象被修改的次数,每对List对象修改一次,modCount都会加1.
Itr类里有一个成员变量expectedModCount,它的值为创建Itr对象的时候List的modCount值。用此变量来检验在迭代过程中List对象是否被修改了,如果被修改了则抛出java.util.ConcurrentModificationException异常。在每次调用Itr对象的next()方法的时候都会调用checkForComodification()方法进行一次检验,checkForComodification()方法中做的工作就是比较expectedModCount 和modCount的值是否相等,如果不相等,就认为还有其他对象正在对当前的List进行操作,那个就会抛出ConcurrentModificationException异常。
我们再来分析一下上面那个例子,当例子程序执行到22行的时候,将list对象里面的“c"删除了,同时list对象的modCount值加1,但是Itr对象的expectedModCount没有变,他们肯定是不相等了。等再一次执行next()方法的时候调用了checkForComodification()方法,这时候就抛出异常了。
我们再将上面那个例子稍微改动一下:将21行改为if(str.equals("d")){,即删除”d"这个元素。运行结果如下:
a
b
c
这时却没有报异常了,但是“e"却没有输出来,这是为什么呢?原因很简单,我们看到Itr的hashNext()方法:
public boolean hasNext() {
return cursor != size;
}
它是通过Itr的对象的cursor与List对象的size值来判断是否还有未迭代的对象,当遍历完“d"的时候cursor=4,删除”d"的时候,List对象的size就会减1,size首先为5,后来变为4,这时候cursor和size是相等的,hasNext()方法返回的是false,就认为遍历结束了,所以删除以后没有进去执行next()方法了,就没有抛出异常了,当然"e"也没有输出来。
为了避免这种异常,我们可以使用CopyOnWriteArrayList来代替ArrayList,CopyOnWriteArrayList支持并发访问,所以同时进行迭代和修改是没有问题的。
最新文章
- NLog在Asp.Net MVC的实战应用
- float4与half4数据类型
- centos7 cannot find a valid baseurl for repo base (转载)
- ORA-00060:等待资源时检测到死锁的一种处理方法
- Eclipse代码提示功能是不是利用反射
- HttpRequest类
- Esper系列(一)初探
- 关于MySQL的分区(partion)
- 查询sql 语句的好坏
- poj 1411 Calling Extraterrestrial Intelligence Again
- mac系统下给文件夹加密方法
- CentOS上javaweb开发环境搭建
- 使用rsync在windows(服务端)与linux(客户端)之间同步
- 【Python3爬虫】拉勾网爬虫
- 【PHP】最详细PHP从入门到精通(一)——想学习PHP的朋友们福利来了!
- Zookeeper环境搭建
- 菜刀(代码执行)函数和命令执行函数详解及Getshell方法
- php 对象教程
- RTSP 与 RTMP 协议 (转)
- ASP.NET Web API 框架研究 Controller创建 HttpController介绍
热门文章
- HDU 4888 Redraw Beautiful Drawings 网络流 建图
- SharePoint SPUtility.SendEmail 发送邮件设置级别
- 《“胡”说IC——菜鸟工程师完美进阶》
- serializeArray()与 serialize()
- @ZooKeeper注册中心安装(单节点)
- 浅谈提升C#正则表达式效率
- Gas Station leetcode java
- 魅族推送 简介 集成 MD
- C# 6.0 的那些事
- python对json的操作总结 zz