对ArrayList的操作我们可以通过索引象来访问,也可以通过Iterator来访问,只要不对ArrayList结构上进行修改都不会造成ConcurrentModificationException,单独用索引对ArrayList进行修改也不会造成该问题,造成该问题主要是在索引和Iterator混用。可以通过JDK的源码来说明该问题。

首先看下AbstractList的Iterator内的代码:

  1. /**
  2. *在Iterator的内部有个expectedModCount 变量,
  3. *该变量每次初始化*Iterator的时候等于ArrayList的modCount,modCount记录了对ArrayList的结构修改次数,
  4. *在通过Iterator对ArrayList进行结构的修改的时候都会将expectedModCount 与modCount同步,
  5. *但是如果在通过Iterator访问的时候同时又通过索引的方式去修改ArrayList的结构的话,
  6. *由于通过索引的方式只会修改modCount不会同步修改expectedModCount 就会导致
  7. *modCount和expectedModCount 不相等就会抛ConcurrentModificationException,
  8. *这也就是Iterator的fail-fast,快速失效的。所以只要采取一种方式操作ArrayList就不会出问题,
  9. *当然ArrayList不是线程安全的,此处不讨论对线程问题。
  10. *
  11. */
  12. int expectedModCount = modCount;
  13. public E next() {
  14. checkForComodification();//判断modeCount与expectedModCount 是否相等,如果不相等就抛异常
  15. try {
  16. E next = get(cursor);
  17. lastRet = cursor++;
  18. return next;
  19. } catch (IndexOutOfBoundsException e) {
  20. checkForComodification();
  21. throw new NoSuchElementException();
  22. }
  23. }
  24. public void remove() {
  25. if (lastRet == -1)
  26. throw new IllegalStateException();
  27. checkForComodification();//同样去判断modeCount与expectedModCount 是否相等
  28. try {
  29. AbstractList.this.remove(lastRet);
  30. if (lastRet < cursor)
  31. cursor--;
  32. lastRet = -1;
  33. expectedModCount = modCount;//此处修改ArrayList的结构,所以要将expectedModCount 于modCount同步,主要是AbstractList.this.remove(lastRet);的remove方法中将modCount++了,导致了modCount与expectedModCount 不相等了。
  34. } catch (IndexOutOfBoundsException e) {
  35. throw new ConcurrentModificationException();
  36. }
  37. }
  38. //判断modCount 与expectedModCount是否相等,如果不相等就抛ConcurrentModificationException异常
  39. final void checkForComodification() {
  40. if (modCount != expectedModCount)
  41. throw new ConcurrentModificationException();
  42. }

故我的结论是:对ArrayList的操作采用一种遍历方式,要么索引,要么Iterator别混用即可。

下面是网上看见别人的解释:写道

Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性

关于List的ConcurrentModificationException的更多相关文章

  1. java.util.ConcurrentModificationException 解决办法(转载)

    今天在项目的中有一个需求,需要在一个Set类型的集合中删除满足条件的对象,这时想当然地想到直接调用Set的remove(Object o)方法将指定的对象删除即可,测试代码:   public cla ...

  2. java.util.ConcurrentModificationException异常处理

    ConcurrentModificationException异常处理 ConcurrentModificationException异常是Iterator遍历ArrayList或者HashMap数组 ...

  3. java.util.ConcurrentModificationException --map

    key:3-key key:/v1.02-key Exception in thread "main" java.util.ConcurrentModificationExcept ...

  4. 偶遇到 java.util.ConcurrentModificationException 的异常

    今天在调试程序 遇到了如此问题 贴上代码来看看稍后分析 List<String> list = null;boolean isUpdate = false;try { list = JSO ...

  5. 集合框架之——迭代器并发修改异常ConcurrentModificationException

    问题: 我有一个集合,如下,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现. 使用普通迭代器出现的异常: ...

  6. 对ArrayList操作时报错java.util.ConcurrentModificationException null

    用iterator遍历集合时要注意的地方:不可以对iterator相关的地方做添加或删除操作.否则会报java.util.ConcurrentModificationException 例如如下代码: ...

  7. Java ConcurrentModificationException异常原因和解决方法

    Java ConcurrentModificationException异常原因和解决方法 在前面一篇文章中提到,对Vector.ArrayList在迭代的时候如果同时对其进行修改就会抛出java.u ...

  8. LinkedList - java.util.ConcurrentModificationException

    package com.test.io; import java.io.BufferedReader; import java.io.FileNotFoundException; import jav ...

  9. java 多线程操作List,已经做了同步synchronized,还会有ConcurrentModificationException,知道为什么吗?

    如题,最近项目里有个模块我做了异步处理方面的事情,在code过程中发现一个颠覆我对synchronized这个关键字和用法的地方,请问各位java开发者们是否对此有一个合理的解释,不多说,我直接贴出问 ...

随机推荐

  1. java web学习总结(二十三) -------------------编写自己的JDBC框架

    一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...

  2. glibc 各版本发布时间以及内核默认glibc版本

    最近有些软件要求glibc 2.14+,centos 6.x自带的版本是2.12的,特查了下glibc 各版本发布时间以及与对应的内核,如下: Complete glibc release histo ...

  3. 关于MySql的1146错误修正

    在Mysql数据库中建立连接Mysql后建立了一个数据库名叫Mysql后删除了系统自动建立的数个表,导入.sql文件运行后,想要运行相关的SQL语句却发现一些未知错误为 Table 'mysql.pr ...

  4. C#模拟HTTP Form请求上传文件

    using System; using System.Collections.Generic; using System.Text; using System.Net; using System.IO ...

  5. sed的应用

    h3 { color: rgb(255, 255, 255); background-color: rgb(30,144,255); padding: 3px; margin: 10px 0px } ...

  6. HTML的doctype和编码

    DOCTYPE Doctype是为了告诉浏览器用哪种版本的html去解析指令,必须位于第一行,在某些版本中需要引入DTD,html5无需引入DTD 中文乱码 原因 浏览器解析代码的编码格式与源代码编码 ...

  7. FineReport制作可动态展开的组织递归树报表

    先看看效果: 报表软件:FineReport 1.分析-与正常查询的对比 如果不做这种树状结构展开的报表的话,正常的SQL应该是这样写的,以单据表为例,假设单据的机构为分公司,经营部 select 分 ...

  8. Spring下如何配置bean

    本次讲述项目背景: 创建Service类,Service下用到dao类.通过在Spring中配置bean,实现在项目启动时,自动加载这个类 本次只讲述配置bean的注意事项,故只给出简单实例: 创建S ...

  9. ddd 聚合根 之 聚合与不聚合 设计

    聚合 不聚合 订单和订单明细 论坛主贴与贴子回复 订单和收货地址(vo)  

  10. ABP督导项目(1)

    创建实体 项目名TQMASP 在领域层创建entities文件夹存放实体类如图 创建Dbcontext public virtual IDbSet<Supervisor> Supervis ...