对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. FlashBuilder项目环境配置

    一 .安装Flash Builder 1.  修改host文件 1.1 找到host文件,复制到桌面修改. 在"C:\Windows\System32\drivers\etc"文件 ...

  2. spider RPC插件化体系

    为了满足灵活扩展的需要,spider支持灵活的自定义插件扩展,从功能上来说,插件和过滤器的差别在于过滤器不会阻止请求的执行同时对于主程序不会有API上的影响(比如servlet 过滤器和监听器)(最多 ...

  3. js 轮播效果

    <!--图片轮播      Start-->                    <div class="pics-ul">               ...

  4. js原生跨域--用script标签实现

    刚刚从培训班学习完,总想写一下东西,自从进入了这个院子,每次出现问题,总是能找到一些答案,给我一些帮助. 作为新手,就写一下简单的吧,院子里面有很多大牛, 说句实话,他们的很多代码我都看不懂. 我就写 ...

  5. Atitit.http httpclient实践java c# .net php attilax总结

    Atitit.http httpclient实践java c# .net php attilax总结 1. Navtree>> net .http1 2. Httpclient理论1 2. ...

  6. Android 7.1 App Shortcuts使用

    Android 7.1 App Shortcuts使用 Android 7.1已经发了预览版, 这里是API Overview: API overview. 其中App Shortcuts是新提供的一 ...

  7. xamarin 一般错误解决办法

    1. android_m2repository_r错误 问题描述: Unzipping failed. Please download https://dl-ssl.google.com/androi ...

  8. React Native JSX value should be expression or a quoted JSX text.

    问题描述:  我在使用props时候, 我的写法是这样的 ... <View> <Person name='john' age=32 gender=true></Pers ...

  9. RunLoop 总结:RunLoop的应用场景(二)

    上一篇讲了使用RunLoop保证子线程的长时间存活,而不是执行完任务后就立刻销毁的应用场景.这一篇就讲述一下RunLoop如何保证NSTimer在视图滑动时,依然能正常运转. 参考资料 好的书籍都是值 ...

  10. javaScript对象-基本包装类型的详解

    本人按书上的内容大致地把javaScript对象划分成“引用类型”.“基本包装类型”和“内置对象”三块内容. 我们这篇先了解下基本包装类型的详细用法吧! 一.我们先解下相关概念: 1.引用类型的值(对 ...