`
sushe1424
  • 浏览: 4802 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
最近访客 更多访客>>
社区版块
存档分类
最新评论

关于List的ConcurrentModificationException

    博客分类:
  • J2SE
 
阅读更多

    上次去一个公司的笔试题里面有一个关于ArrayList的remove问题,今天突然想到以前遇到的ConcurrentModificationException问题,所以在此总结一下,以便以后查阅。

    对ArrayList的操作我们可以通过索引象来访问,也可以通过Iterator来访问,只要不对ArrayList结构上进行修改都不会造成ConcurrentModificationException,单独用索引对ArrayList进行修改也不会造成该问题,造成该问题主要是在索引和Iterator混用。可以通过JDK的源码来说明该问题。

   首先看下AbstractList的Iterator内的代码:

 

/**
*在Iterator的内部有个expectedModCount 变量,
*该变量每次初始化*Iterator的时候等于ArrayList的modCount,modCount记录了对ArrayList的结构修改次数,
*在通过Iterator对ArrayList进行结构的修改的时候都会将expectedModCount 与modCount同步,
*但是如果在通过Iterator访问的时候同时又通过索引的方式去修改ArrayList的结构的话,
*由于通过索引的方式只会修改modCount不会同步修改expectedModCount 就会导致
*modCount和expectedModCount 不相等就会抛ConcurrentModificationException,
*这也就是Iterator的fail-fast,快速失效的。所以只要采取一种方式操作ArrayList就不会出问题,
*当然ArrayList不是线程安全的,此处不讨论对线程问题。
*
*/
int expectedModCount = modCount;
public E next() {
            checkForComodification();//判断modeCount与expectedModCount 是否相等,如果不相等就抛异常
	    try {
		E next = get(cursor);
		lastRet = cursor++;
		return next;
	    } catch (IndexOutOfBoundsException e) {
		checkForComodification();
		throw new NoSuchElementException();
	    }
}

public void remove() {
	 if (lastRet == -1)
		throw new IllegalStateException();
          checkForComodification();//同样去判断modeCount与expectedModCount 是否相等

	  try {
		AbstractList.this.remove(lastRet);
		if (lastRet < cursor)
		    cursor--;
		lastRet = -1;
		expectedModCount = modCount;//此处修改ArrayList的结构,所以要将expectedModCount 于modCount同步,主要是AbstractList.this.remove(lastRet);的remove方法中将modCount++了,导致了modCount与expectedModCount 不相等了。
	   } catch (IndexOutOfBoundsException e) {
		throw new ConcurrentModificationException();
	   }
}

//判断modCount 与expectedModCount是否相等,如果不相等就抛ConcurrentModificationException异常
final void checkForComodification() {
	 if (modCount != expectedModCount)
	      throw new ConcurrentModificationException();
}
 

故我的结论是:对ArrayList的操作采用一种遍历方式,要么索引,要么Iterator别混用即可。

下面是网上看见别人的解释:写道

Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性
 

 

 

 

分享到:
评论

相关推荐

    java.util.ConcurrentModificationException 异常问题详解1

    Java.util.ConcurrentModificationException 异常问题详解 ConcurrentModificationException 异常是 Java 中一个常见的异常,它发生在 Iterator 遍历集合时,集合同时被修改引起的异常。在 Java 中,集合类如 ...

    java的list取之方法

    然而,给出的部分内容却是一段关于导入Excel文件到Web应用中的代码片段,并没有直接涉及List的具体操作方法。因此,我们将结合标题与描述,围绕Java中List的相关知识点进行详细阐述。 ### Java中的List概述 在Java...

    Iterator遍历过程中list删除导致异常

    在Java编程中,`Iterator`是用于遍历集合(如`List`, `Set`等)的重要工具。然而,当我们尝试在使用`Iterator`遍历集合的过程中直接修改集合时,可能会遇到`ConcurrentModificationException`异常。这个异常通常发生...

    Java源码解析ArrayList及ConcurrentModificationException

    bject[initialCapacity]; } else if (initialCapacity == 0) {...同时,需要注意在并发环境下使用ArrayList可能会遇到`ConcurrentModificationException`,应当避免在遍历过程中修改集合,或者选择线程安全的数据结构。

    java 集合并发操作出现的异常ConcurrentModificationException

    在Java编程中,`ConcurrentModificationException`是一个常见的运行时异常,主要出现在多线程环境下对集合类(如List、Set、Map等)进行并发修改时。然而,这个异常不仅限于多线程环境,即使在单线程中,如果在遍历...

    java中List对象集合的遍历方法(三个)

    如果在遍历过程中需要移除元素,必须使用`it.remove()`,直接调用`list.remove()`会导致并发修改异常(ConcurrentModificationException)。 ### 第二种:增强型for循环(foreach) ```java for (A a : list) { /...

    Java 实例 - List 循环移动元素源代码+详细指导教程.zip

    迭代器是Java集合框架提供的一种统一的遍历方式,它可以安全地删除元素,而不会抛出ConcurrentModificationException。以下是一个使用迭代器移动元素的例子: ```java List&lt;String&gt; list = new ArrayList(); // ...

    在list集合中输入元素,去除重复的元素并输出

    根据给定文件的信息,本文将详细介绍如何在Java的List集合中去除重复元素的三种方法:使用for循环、使用迭代器以及利用HashSet的特性。 ### 一、使用for循环去除重复元素 这种方法的基本思想是通过双重循环来遍历...

    Java List简介_动力节点Java学院整理

    使用 ListIterator 时,需要注意并发修改异常(ConcurrentModificationException),当在迭代过程中直接通过集合对象修改集合时,可能会抛出此异常。因此,推荐在迭代时仅使用迭代器的方法来操作元素。 总的来说,...

    HashMap和List遍历方法及如何遍历删除元素总结

    HashMap和List遍历方法及如何遍历删除元素总结 HashMap和List都是Java中最常用的数据结构,它们都可以用来存储和操作数据。然而,在遍历和删除元素时,需要小心地处理,以免出现问题。下面总结了HashMap和List的...

    【IT十八掌徐培成】Java基础第10天-04.List-迭代器-对象等价性.zip

    4. **迭代器与List的关系**:在处理List时,迭代器是首选的遍历方式,因为它提供了一种安全的、避免并发修改异常(ConcurrentModificationException)的方式。当在一个线程中使用迭代器遍历List,而在另一个线程中...

    Java集合Collection、List、Set、Map使用详解

    使用迭代器的主要好处是可以安全地修改集合,因为它在遍历时不会抛出`ConcurrentModificationException`异常。 - `hasNext()`:判断集合中是否有更多的元素。 - `next()`:返回集合中的下一个元素。 - `remove()`:...

    Java List 用法实例详解

    ListIterator 可以用于迭代 List 集合中的元素,但是在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生 ConcurrentModificationException 异常。 以下是 List 集合的常用方法的详解: 1.add(int ...

    java中List的用法.pdf

    - **迭代器(Iterator)**:`Iterator`是Java集合框架的一部分,它提供了一种安全的方式来遍历集合,可以方便地进行添加、删除操作,且不会抛出`ConcurrentModificationException`。示例代码中的`it.hasNext()`和`...

    详解Java 集合类 List 的那些坑

    在直接遍历 List 集合元素时增加、删除元素会报错,例如使用 for 循环遍历 List 时删除元素,会抛出 ConcurrentModificationException 异常。解决方法是使用 Iterator 迭代器遍历 List,并使用 Iterator 的 remove ...

    内置迭代器的linked list例题

    此外,如果在迭代期间直接修改集合(如使用`add()`、`remove()`等方法,而不是通过迭代器),可能会导致`ConcurrentModificationException`,因为这破坏了迭代器的内部状态。 总结来说,Java的LinkedList与内置迭代...

    java中循环遍历删除List和Set集合中元素的方法(推荐)

    在Java编程中,遍历并删除集合(如List或Set)中的元素是一项常见的操作,但如果不正确地执行,可能会导致`ConcurrentModificationException`异常。这个异常通常在尝试修改正在迭代的集合时出现,因为Java的集合迭代...

    Java中List集合的遍历实例详解

    此外,foreach循环不能在遍历过程中修改集合,否则会抛出`ConcurrentModificationException`异常。 3. **索引遍历** 最传统的方式是通过索引来遍历List集合,这种方式适用于需要访问元素索引的情况: ```java ...

    Java list利用遍历进行删除操作3种方法解析

    这个示例中,会抛出 ConcurrentModificationException 异常,因为在遍历 list 时,不能修改 list 的内容。为了解决这个问题,可以使用 CopyOnWriteArrayList,避免这种异常: ```java CopyOnWriteArrayList&lt;String&gt;...

    Java如何在List或Map遍历过程中删除元素

    使用For-each循环遍历List时,不能直接在循环体中调用`remove()`方法,因为这会导致`ConcurrentModificationException`。这是因为For-each循环内部使用的是迭代器,而迭代器不支持在遍历过程中直接修改集合。示例...

Global site tag (gtag.js) - Google Analytics