java java.util.ConcurrentModificationException 原因以及解决方案

简介:

原文:http://blog.csdn.net/traceofsun/article/details/5820925

用iterator遍历集合时要注意的地方:不可以对iterator相关的地方做添加或删除操作。

下面用List为例来说明为什么会报 ConcurrentModificationException  这个异常,其它集合类似可以自己思考。

 

public static void main(String[] args)
 {
  List<String> set = new ArrayList<String>();
  set.add("a10001");
  set.add("a10002");
  set.add("a10003");
  set.add("a10004");
  set.add("a10005");
  set.add("a10006");
  set.add("a10007");
  
  List<String> del = new ArrayList<String>();
  del.add("a10003");
  del.add("a10004");
  del.add("a10005");
  
  for(String str : set)
  {
   if(del.contains(str))
   {
    set.remove(str);
   }
  }
 }

运行这段代码的结果

Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
 at java.util.AbstractList$Itr.next(Unknown Source)
 at com.debug.Debug.main(Debug.java:28)

大家都知道for(String str : set) 这句话实际上是用到了集合的iterator() 方法

在iterator的时候是产生了一个List的内部类Itr

JDK源码

public Iterator<E> iterator() {
   return new Itr();
}

在new Itr()时有一个关键性的操作 

/**
  * The modCount value that the iterator believes that the backing
  * List should have.  If this expectation is violated, the iterator
  * has detected concurrent modification.
  */
 int expectedModCount = modCount;

 

再回头看一下List 的 remove方法

 public boolean remove(Object o) {
 if (o == null) {
            for (int index = 0; index < size; index++)
  if (elementData[index] == null) {
      fastRemove(index);
      return true;
  }
 } else {
     for (int index = 0; index < size; index++)
  if (o.equals(elementData[index])) {
      fastRemove(index);
      return true;
  }
        }
 return false;
    }
 
private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // Let gc do its work
    }
 


再看一下 iterator.next()操作

public E next() {
            checkForComodification();
     try {
  E next = get(cursor);
  lastRet = cursor++;
  return next;
     } catch (IndexOutOfBoundsException e) {
  checkForComodification();
  throw new NoSuchElementException();
     }
 }
 
final void checkForComodification() {
     if (modCount != expectedModCount)
  throw new ConcurrentModificationException();
 }
 

相信看到这儿大家已经应该明白了为什么会出现在这个异常了。

总结:

  iterator 时 将expectedModCount = modCount 在remove()时 modCount++ 在next()时

 if (modCount != expectedModCount)
  throw new ConcurrentModificationException();

 

一旦删除或添加元素后 modCount ,expectedModCount 这两个值就会不一致 当next时就会报ConcurrentModificationException

 

了解了原由,解决方案就很简单了 在遍历时用一个集合存放要删除的对象 在遍历完后 调用removeAll(Collection<?> c) 就OK了。



相关文章
|
1月前
|
关系型数据库 MySQL Java
【IDEA】java后台操作mysql数据库驱动常见错误解决方案
【IDEA】java后台操作mysql数据库驱动常见错误解决方案
51 0
|
6天前
|
Java API Apache
|
28天前
|
Java
短频快task的java解决方案
本文探讨了Java自带WorkStealingPool的缺陷,特别是在任务中断方面的不足。普通线程池在处理短频快任务时存在锁竞争问题,导致性能损耗。文章提出了一种基于任务窃取机制的优化方案,通过设计合理的窃取逻辑和减少性能损耗,实现了任务的高效执行和资源的充分利用。最后总结了不同场景下应选择的线程池类型。
|
1月前
|
小程序 Java
小程序访问java后台失败解决方案
小程序访问java后台失败解决方案
42 2
|
2月前
|
传感器 监控 数据可视化
【Java】智慧工地解决方案源码和所需关键技术
智慧工地解决方案是一种新的工程全生命周期管理理念。它通过使用各种传感器、数传终端等物联网手段获取工程施工过程信息,并上传到云平台,以保障数据安全。
79 7
|
1月前
|
存储 前端开发 Java
浅谈Java中文乱码浅析及解决方案
浅谈Java中文乱码浅析及解决方案
51 0
|
1月前
|
Java
Error:java: 无效的目标发行版: 11解决方案
Error:java: 无效的目标发行版: 11解决方案
64 0
|
1月前
|
Java Maven Spring
用Spring导致的无法运行Java文件的问题的解决方案
本文提供了解决在IntelliJ IDEA社区版中使用Spring Initializr插件创建Spring项目后,Java文件无法运行的问题的方法,主要是通过加载Maven项目来解决。
63 0
|
3月前
|
存储 NoSQL Java
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这篇文章是关于Java面试中的分布式架构问题的笔记,包括分布式架构下的Session共享方案、RPC和RMI的理解、分布式ID生成方案、分布式锁解决方案以及分布式事务解决方案。
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
|
3月前
|
Java 开发者
在Java编程中,if-else与switch作为核心的条件控制语句,各有千秋。if-else基于条件分支,适用于复杂逻辑;而switch则擅长处理枚举或固定选项列表,提供简洁高效的解决方案
在Java编程中,if-else与switch作为核心的条件控制语句,各有千秋。if-else基于条件分支,适用于复杂逻辑;而switch则擅长处理枚举或固定选项列表,提供简洁高效的解决方案。本文通过技术综述及示例代码,剖析两者在性能上的差异。if-else具有短路特性,但条件增多时JVM会优化提升性能;switch则利用跳转表机制,在处理大量固定选项时表现出色。通过实验对比可见,switch在重复case值处理上通常更快。尽管如此,选择时还需兼顾代码的可读性和维护性。理解这些细节有助于开发者编写出既高效又优雅的Java代码。
47 2