`
Arron.li
  • 浏览: 136034 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

解决ArrayList的ConcurrentModificationException

    博客分类:
  • Java
阅读更多

1 问题 :在list<String> 中清空所有的记录,只使用使用单循环,不使用removeAll()

 

2 可以写出五种方式,代码如下:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListRemoveTest {
	 public static void main(String[] args) {  
		         ListRemoveTest test = new ListRemoveTest();  
		           
		         System.out.println("-1-使用jdk5.0以后的增强for循环去remove");  
		         List<String> list = test.buildList();  
		         try {  
		             for (String str : list) {  
		                 list.remove(str);  
		             }  
		         } catch (Exception e) {  
		             // java.util.ConcurrentModificationException  
		             e.printStackTrace();   
		         }  
		   
		         System.out.println("-2-使用Iterator的remove");  
		         list = test.buildList();  
		         try {  
		             Iterator<String> iterator = list.iterator();  
		             while (iterator.hasNext()) {
		            	 iterator.next();
		                 iterator.remove();  
		             }  
		         } catch (Exception e) {  
		             // java.lang.IllegalStateException  
		             e.printStackTrace();  
		         }  
		   
		         System.out.println("-3-iterator遍历+list的remove");  
		         try {  
		             list = test.buildList();  
		             for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {  
		                 String str = (String) iterator.next();  
		                 list.remove(str);  
		             }  
		         } catch (Exception e) {  
		             // java.util.ConcurrentModificationException  
		             e.printStackTrace();  
		         }  
		           
		         System.out.println("-4-使用list的remove(int)方法. [由后向前删除]");  
		         list = test.buildList();  
		         for (int i = list.size(); i > 0; i--) {  
		             list.remove(i - 1);  
		         }  
		   
		         System.out.println("-5-使用list的remove(int)方法. [由前向后删除]");  
		         list = test.buildList();  
		         for (int i = 0; i < list.size(); i++) {  
		             list.remove(0);  
		         }  
		     }  
		   
		     private List<String> buildList() {  
		         List<String> list = new ArrayList<String>();  
		         list.add("a");  
		         list.add("b");  
		         list.add("c");  
		         return list;  
		     }  
}

 3运行结果如下:

-1-使用jdk5.0以后的增强for循环去remove
java.util.ConcurrentModificationException
-2-使用Iterator的remove
-3-iterator遍历+list的remove
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:781)
	at java.util.ArrayList$Itr.next(ArrayList.java:753)
	at com.jdk.ListRemoveTest.main(ListRemoveTest.java:14)
java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:781)
	at java.util.ArrayList$Itr.next(ArrayList.java:753)
	at com.jdk.ListRemoveTest.main(ListRemoveTest.java:39)
-4-使用list的remove(int)方法. [由后向前删除]
-5-使用list的remove(int)方法. [由前向后删除]

2,4,5运行正常,1,3抛出

java.util.ConcurrentModificationException

 

4问题原因:

1,3都是因为list的长度改变,Iterator执行next()方法时,调用checkForComodification()时出错,1,3是同一个问题,这两个方法remove操作都是执行的是ArrayList中的remove方法,根本原因在于expectedModCount与modCount他们的不相等,由于执行了ArrayList中的remove(),modCount在每一次循环值会发生改变,而expectedModCount并没有发生,在执行checkForComodification()方法就会抛出异常。

2之所以正确运行是因为调用了Iterator的remove方法,4,5不会执行checkForComodification()操作,所以不会出现这种异常。

 

5结论 :在执行remove()不要将ArrayList 与Interator混合使用,单独使用Interator以及ArrayList的删除都是OK的

6参考的源码

Iterator的next()方法:

        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

 Iterator的remove()方法:

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                //当执行remove操作后,将改变的modCount值重新赋给expectedModCount
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

 ArrayList的remove()方法:

 

 

  /**
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If the list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns <tt>true</tt> if this list
     * contained the specified element (or equivalently, if this list
     * changed as a result of the call).
     *
     * @param o element to be removed from this list, if present
     * @return <tt>true</tt> if this list contained the specified element
     */
 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 remove method that skips bounds checking and does not
     * return the value removed.
     */
    private void fastRemove(int index) {
        //此处modCount发生了改变,但expectedModCount仍然未发生变化,所以再执行下一次循环时执行
        //Interator的next()方法当然会报错
        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
    }
2
0
分享到:
评论
3 楼 jptiancai 2016-02-02  
提供下第六种做法,多用些内存,遍历set的时候,用list删除
         System.out.println("-6-使用set"); 
        
         Set<String> s = new HashSet<String>();
         s.addAll(list);
         for (String str : s) {
        list.remove(str);
}
2 楼 Arron.li 2010-04-16  
首先非常感谢一楼的建议,自己确实对这个数据结构的本质理解的不够深刻,我会继续认真分析这个数据结构,希望读者多提您的建议和参考。
1 楼 sdh5724 2010-04-16  
虽然说对了现象, 也规避了现象。问题分析的角度完全不对。 关键还是要理解这个数据结构构建的原理。 ConcurrentModificationException 这错误本身是为“提醒”程序员并发修改数据结构使用的, 因为这个不是写线程安全的数据结构, 不是为了这个循环删除的目的。从本质上去理解, 你会轻松很多。

相关推荐

    Java源码解析ArrayList及ConcurrentModificationException

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

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

    这个示例代码尝试在遍历 ArrayList 时删除其中的一个元素,这将导致 ConcurrentModificationException 异常。 那么,为什么会抛出这个异常呢?我们可以通过查看 ArrayList 的源码来了解原因。ArrayList 的 iterator...

    我的ArrayList实现

    如果多个线程同时修改ArrayList,可能会导致数据不一致或抛出ConcurrentModificationException。若需在多线程环境中使用,可以考虑使用Collections.synchronizedList对ArrayList进行包装,或者使用线程安全的...

    从原码解析ArrayList

    《深入解析ArrayList》 ArrayList是Java集合框架中常用的列表实现之一,它继承自AbstractList,并实现了List接口。本文将从ArrayList的源码出发,详细解析其底层实现、默认初始容量、RandomAccess接口以及添加和...

    比较Vector、ArrayList和hashtable hashmap

    在使用时,另一个线程改变了 Vector,那么将会抛出 ConcurrentModificationException 异常。因此,如果多线程并发访问 Vector,通常需要通过 synchronized 关键字进行同步控制。 HashMap 类 HashMap 是一个散列表,...

    ArrayList.md

    老猿说说-ArrayList MD文件 1. 所有的操作都是线程安全的,我们在使用时,无需再加锁; 2. 多个线程同时进行put、remove等操作时并不会阻塞,可以同时进行,和HashTable不同,HashTable在操作时,会锁住整个Map; 3. ...

    jdk源码阅读一:ArrayList

    如果在迭代过程中有其他线程修改了ArrayList的结构,则迭代器会抛出`ConcurrentModificationException`异常。这一机制有助于检测并发修改的问题,并提示开发者修复代码。 #### 七、结论 通过深入分析ArrayList的...

    ArrayList的学习821.docx

    在多线程环境下,多个线程同时对ArrayList进行操作(尤其是修改操作,如add、remove等)可能导致数据不一致或抛出`ConcurrentModificationException`。为了使ArrayList在多线程环境下安全使用,可以借助`Collections...

    硬核ArrayList源码分析,答应我每天看一遍好么

    《硬核ArrayList源码分析——深入理解Java集合框架》 ArrayList是Java集合框架中的一个重要组成部分,它是基于动态数组实现的列表。...每天温习ArrayList的源码,无疑能提升我们的编程素养和问题解决能力。

    遍历并批量删除容器中元素出现ConcurrentModificationException原因及处置

    `ConcurrentModificationException`的根源在于`ArrayList`、`LinkedList`等集合类的实现。它们维护了一个迭代器,当检测到在迭代过程中有非迭代器自身的修改操作时,就会抛出此异常。这是为了保护集合的完整性,...

    Java中ArrayList和Vector的区别共2页.p

    - ArrayList和Vector的迭代器在遍历元素时性能相近,但因为Vector的线程安全性,如果在迭代过程中其他线程修改了Vector,迭代器会抛出`ConcurrentModificationException`,而ArrayList则不会。 6. **使用场景**: ...

    ArrayList上机练习1

    - `Iterator`遍历:`Iterator`允许我们在遍历过程中删除元素,而不会导致`ConcurrentModificationException`。它不依赖于索引,因此在某些情况下可能比基于索引的遍历更快。然而,如果只是简单地遍历和访问元素,...

    ArrayList.docx

    2. **解决办法**: - 使用线程安全的`Vector`替代`ArrayList`。 - 通过`Collections.synchronizedList()`方法将`ArrayList`转换为线程安全的版本。 - 使用`CopyOnWriteArrayList`,它采用写时复制策略,读操作时...

    Java 集合框架(2-9)-Collection - ArrayList 源码解析.pdf

    当ArrayList在迭代过程中被修改(例如添加、删除元素),迭代器会立即抛出ConcurrentModificationException,以防止数据的不一致性。这是一种设计模式,用于快速检测并发修改,以避免潜在的错误。 总的来说,...

    Java ArrayList遍历修改代码实例解析

    然而,在遍历 ArrayList 时,如果需要删除某些元素,可能会遇到 ConcurrentModificationException 异常。今天,我们将讨论如何正确地遍历和修改 ArrayList。 遍历 ArrayList 的正确方法 在遍历 ArrayList 时,不能...

    java 中ArrayList迭代的两种实现方法

    使用Iterator的好处是它可以检测并处理并发修改异常(ConcurrentModificationException),这是在遍历集合时尝试修改集合的常见错误。以下是如何使用Iterator遍历ArrayList: ```java ArrayList&lt;String&gt; arrayList ...

    ArrayList源码解析(数据结构及底层实现)(csdn)————程序.pdf

    - 为了避免并发修改异常(`ConcurrentModificationException`),在多线程环境下使用 ArrayList 时,应使用 `Collections.synchronizedList` 或 `CopyOnWriteArrayList`。 通过了解 ArrayList 的源码,我们可以更好...

    java.util.ConcurrentModificationException 解决方法

    `java.util.ConcurrentModificationException` 是一个在 Java 中常见的运行时异常,它通常发生在多线程环境中,当一个线程正在遍历一个集合(如 `ArrayList`, `HashMap` 等),而另一个线程同时尝试修改这个集合时。...

    ArrayList.java

    iterator和listIterator方法是快速失败的 :如果列表在任何时间从结构上修改创建迭代器之后,以任何方式,除了通过迭代器自身的remove或add方法,迭代器都将抛出ConcurrentModificationException 。 因此,在并发的...

Global site tag (gtag.js) - Google Analytics