在使用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支持并发访问,所以同时进行迭代和修改是没有问题的。

使用迭代器遍历List的时候修改List报ConcurrentModificationException异常原因分析的更多相关文章

  1. 修改List报ConcurrentModificationException异常原因分析

    使用迭代器遍历List的时候修改List报ConcurrentModificationException异常原因分析 在使用Iterator来迭代遍历List的时候如果修改该List对象,则会报jav ...

  2. 使用迭代器遍历List的时候修改List报ConcurrentModificationException异常的解决办法

    为了避免这种异常,我们可以使用CopyOnWriteArrayList来代替ArrayList,CopyOnWriteArrayList支持并发访问,所以同时进行迭代和修改是没有问题的.

  3. 在多线程的情况下是由Iterator遍历修改集合对象,报ConcurrentModificationException()异常的根因分析

    遍历List时抛ConcurrentModificationException异常原理分析     http://www.blogjava.net/houlinyan/archive/2008/04/ ...

  4. 遍历ArrayList时同时修改引发的问题

    看见一篇博客,没有写完整,于是增补了一下: 博客原文:http://www.cnblogs.com/alipayhutu/archive/2012/08/11/2634073.html 注:黄色字体为 ...

  5. Redis Scan迭代器遍历操作原理(一)

    Redis在2.8.0版本新增了众望所归的scan操作,从此再也不用担心敲入了keys*, 然后举起双手看着键盘等待漫长的系统卡死了··· 命令的官方介绍在这里, 中文版由huangz同学细心翻译了, ...

  6. Java集合——遍历集合元素并修改

    Java集合——遍历集合元素并修改 摘要:本文主要总结了遍历集合的方式,以及在遍历时修改集合要注意的问题. 遍历Collection 对List和Set的遍历,有四种方式,下面以ArrayList为例 ...

  7. - 集合 遍历 foreach Iterator 并发修改 ConcurrentModificationException MD

    目录 目录 为什么不能在 foreach 循环里进行元素的 remove/add 操作 背景 foreach 循环 问题重现 fail-fast remove/add 做了什么 正确姿势 直接使用普通 ...

  8. Java List中迭代器遍历

    在java中,List接口从Collection接口中继承了 iterator()函数,返回值是一个T类型的迭代器(泛型),T是List中元素的类型 public class TestListAndI ...

  9. java 迭代器遍历List Set Map

    Iterator接口: 所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现Iterator接口的对象 Iterator对象称作为迭代器,用以方便的对容器内元素的遍历 ...

随机推荐

  1. 数据访问:Implementing Efficient Transactions

    An OLTP scenario is characterized by a large number of concurrent operations that create, update, an ...

  2. 权力的游戏第一季/全集Game of Thrones迅雷下载

    <权力的游戏>是一部中世纪史诗奇幻题材的电视连续剧,该剧以美国作家乔治·R·R·马丁的奇幻巨作<冰与火之歌>七部曲为基础改编创作. 故事背景中虚构的世界,分为两片大陆:位于西面 ...

  3. 安卓开发(Java)中关于final关键字与线程安全性

    前言 学习新知识固然重要,但是时常往回看看,温故知新是很必要的.回顾一下线程安全性和final关键字. 正文 从Java 5开始,final keyword一个特殊用法是在并发库中一个非常重要且经常被 ...

  4. [转]CENTOS 使用RSYNC+INOTIFY实现文件实时自动同步

    FROM : http://www.qiansw.com/centos-rsync-inotify-file-sync.html 生产环境中的两台web服务器,有个目录需要完全一样.使用rsync和i ...

  5. Spring Scheduler定时任务 + Quartz

    原文地址: https://blog.csdn.net/revitalizing/article/details/61420556 版权声明:本文为博主原创文章,未经博主允许不得转载. https:/ ...

  6. ASP.NET MVC4 HtmlHelper扩展类,实现分页功能 @Html.ShowPageNavigate

    本文主要做了一个HtmHelper类的分页扩展函数,方便在视图中调用,有需要的朋友可以参考一下,希望对大家有所帮助. 1.扩展HtmlHelper类方法ShowPageNavigate output. ...

  7. 用java打暴雪星际争霸(2)——执行測试机器人

    原创内容.转载请注明. 在上一节安装完成后.或者您直接打开我分享的虚拟机后,我如今将解说怎样启动測试机器人. 第一步,打开Eclipse,导入机器人演示样例项目,如图所看到的. 第二步,我们能够看到就 ...

  8. Maven 默认插件以及功能

    Maven 默认插件 已知 Maven 使用 plugin 来执行实际操作的,在默认情况下,Maven 会绑定以下几个插件来完成基本操作. plugin function life cycle pha ...

  9. EntityFramework6 快速入门教程【转】

    https://www.cnblogs.com/wujingtao/p/5401113.html 不得不说EF在国内实在是太小众,相关的技术文章真实屈指可数,而且很多文章都很旧了,里面使用的版本跟如今 ...

  10. Java反编译代码分析(一)

    浅析如何读懂这种反编译过来的文件,不喜勿喷. 赋值 Node node; Node node1 = _$3.getChildNodes().item(0); node1; node1; JVM INS ...