对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. C#连接Access与SQL Server

    1.连接Access数据库 string strConnection = "Provider=Microsoft.Ace.OleDb.12.0; Data Source=" + S ...

  2. 搜狗输入法linux安装 以及 12个依赖包下载链接分享

    搜狗输入法linux安装版,先安装各种依赖包,大概12个依赖,可能中途还需要其他依赖,可以效仿解决依赖问题.如图这12个文件要是手动点击下载,那也太笨点了,我们要用shell命令批量下载.命令如下:w ...

  3. webuploader上传文件,图片

    WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件.官方地址:http://fex.baidu.com/webupload ...

  4. SpringMVC类型转换器、属性编辑器

    对于MVC框架,参数绑定一直觉得是很神奇很方便的一个东西,在参数绑定的过程中利用了属性编辑器.类型转换器 参数绑定流程 参数绑定:把请求中的数据,转化成指定类型的对象,交给处理请求的方法 请求进入到D ...

  5. 关于python字符串连接的操作

    python字符串连接的N种方式 注:本文转自http://www.cnblogs.com/dream397/p/3925436.html 这是一篇不错的文章 故转 python中有很多字符串连接方式 ...

  6. Java 相关书籍

    Effective Java 中文第二版: Java并发编程实践: Java核心技术(原书第8版)卷I_基础知识: Java核心技术(原书第8版)卷II_高级特性: 深入理解Java虚拟机 JVM高级 ...

  7. mysql比较时间大小unix_timestamp

    使用unix_timestamp方法进行比较,将字符型的时间,转成unix时间戳 select * from t1 where unix_timestamp(time1) > unix_time ...

  8. mkdir,rmdir,cp,rm,mv,cat,touch用法

    一.mkdir新建目录 1.进入tmp目录,查看该目录下面的子目录 [root@localhost ~]# cd /tmp[root@localhost tmp]# lshsperfdata_root ...

  9. 为Ubuntu的root设置密码

    问题描述:当安装好Ubuntu系统的时候,root用户没有密码,需要设置. 解决方法:

  10. HTML5全屏(Fullscreen)API详细介绍

    // 整个页面 onclick=   launchFullScreen(document.documentElement); // 某个元素 launchFullScreen(document.get ...