对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. bzoj1036--树链剖分

    模板题... #include<iostream> #include<cstdio> #include<cstring> using namespace std; ...

  2. 16款最佳的 jQuery Time Picker 时间选择插件

    jQuery 插件可以为你做许多事情,你可以很容易地把这些插件集成到您的网站.网络上的 jQuery 日期选择器和日历插件很多,但找不到很满意的时间选择器插件. 在这里,我们收集了最好的一组 jQue ...

  3. SAP CRM 通过调试观察CL_CRM_BOL_ENTITY中的数据

    这个(BOL里面)最重要的类值得一看. BOL中的每条记录都会在CL_CRM_BOL_ENTIT中表示.至今,我们已经写过一些事件处理器,并且我们已经直接或间接的通过这个类工作.在业务场景中,我们也许 ...

  4. 将Oracle数据库中的数据写入Excel

    将Oracle数据库中的数据写入Excel 1.准备工作 Oracle数据库"TBYZB_FIELD_PRESSURE"表中数据如图: Excel模板(201512.xls): 2 ...

  5. grunt-笔记

    package.json: { "name": "grunt-uglify", "version": "1.0.0", ...

  6. Bluemix中国版体验(一)

    很高兴终于拿到了中国版Bluemix的账号!中国版的Bluemix是由世纪互联运营的,这也是世纪互联继Microsoft Azure,Office 365之后运营的又一个国际一线大品牌的云服务. 中国 ...

  7. Bootsrap基本应用

    Bootsrap 用法: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  8. 用grunt搭建web前端开发环境

    1.前言 本文章旨在讲解grunt入门,以及讲解grunt最常用的几个插件的使用. 2.安装node.js Grunt和所有grunt插件都是基于nodejs来运行的,如果你的电脑上没有nodejs, ...

  9. ubuntu-Linux系统读取USB摄像头数据(uvc)

    这几天在做小车的过程中,需要用到图像采集.我想现在用的摄像头是UVC免驱的.根据国嵌的教程中有一个gspca摄像头的程序.我发现把gspca的采集程序用到uvc上时,在显示图像的时候提示没有huffm ...

  10. c#根据绝对路径获取 带后缀文件名、后缀名、文件名

    zz   C#根据绝对路径获取 带后缀文件名.后缀名.文件名 1.c#根据绝对路径获取 带后缀文件名.后缀名.文件名. string str =" F:\test\Default.aspx& ...