对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. 大量数据快速导出的解决方案-Kettle

    1.开发背景 在web项目中,经常会需要查询数据导出excel,以前比较常见的就是用poi.使用poi的时候也有两种方式,一种就是直接将集合一次性导出为excel,还有一种是分批次追加的方式适合数据量 ...

  2. CentOS6.7搭建LNMP环境

    1:查看环境: [root@localhost ~]# cat /etc/redhat-release 2:关掉防火墙 #重启后生效开启 [root@localhost ~]# chkconfig i ...

  3. 浏览器对localstorage的支持情况以及localstorage在saas系统中的应用实践思考

    首先,还是要说,任何一种新特性的引入,通常有着其特有的场景和解决的目标需求,localstorage也一样.在我们的应用场景中,主要在金融业务服务的saas系统.其中涉及很多更改频率很多的元数据的客户 ...

  4. angularjs中的filter(过滤器)——格式化日期的date

    date过滤器的功能是基于要求的格式格式化一个日期成为一个字符串. 格式化字符串的基本参数: 'yyyy': 用4位数字表示年(例如:AD 1 => 0001, AD 2010 => 20 ...

  5. js Function()构造函数

    var scope="global";    function constructFunction(){        var scope="local";   ...

  6. Golang Web开发时前端出现谜之空白换行的坑

    在使用Golang做Web开发时,有时候渲染出来的模板在前台显示时会出现一些奇怪的空白换行,具体特征就是查看css样式表并没有相关定义的空白部分. 分析: 查看出现问题页面的网页源代码,复制空白换行部 ...

  7. Mac下查看端口占用

    netstat命令 netstat -an | grep 端口号 lsof命令 lsof -i:端口号

  8. JokeClient-Swift 仿写学习

    required init?(coder aDecoder: NSCoder) 可失败构造器 在init关键字后面添加问号(init?). 可失败构造器会创建一个类型为自身类型的可选类型的对象.你通过 ...

  9. C#委托的介绍(delegate、Action、Func、predicate)

    委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递.事件是一种特殊的委托. 1.委托的声明 (1). delegate delegate我们常用到的一种声明   Deleg ...

  10. 让代码更简单——自定义toBean实现

    经过历时三天的鏖战,终于将阶段性项目——新闻发布系统做完了.在编码过程中,发现了很多冗余代码,统一流程,却需要不断重复编码——将用户输入实例化为对象的过程. 例: Person.set("i ...