`
lizhuang
  • 浏览: 906021 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

并发下remove集合元素要注意的事情

    博客分类:
  • Java
 
阅读更多
1.不要在foreach循环里进行元素的remove/add操作,remove元素请使用iterator方式,如并发操作,需要对iterator对象加锁.

反倒:
List<String> strs = new ArrayList<String>();
		strs.add("1");
		strs.add("2");
		
		for (String str : strs) {
			if("1".equals(str)){
				strs.remove(str);
			}
		}

这个反例,在并发执行的时候是不安全的.
正确的做法是
Iterator<String> it = strs.iterator();
while(it.hasNext()){

  String temp = it.next();
  if(删除元素的条件){
     it.remove());
  }
}


原因是Java自带的一种迭代器快速失败机制.
迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证,快速失败迭代器会尽最大努力抛出 ConcurrentModificationException,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。

它是Java集合的一种错误检测机制。当多个线程对集合进行结构上的改变的操作时,有可能会产生fail-fast机制。记住是有可能,而不是一定。

     ConcurrentModificationException不会始终指出对象已经由不同线程并发修改,如果单线程违反了规则,同样也有可能会抛出该异常。

     迭代器在调用next()、remove()方法时都是调用checkForComodification()方法,该方法主要就是检测modCount == expectedModCount ? 若不等则抛出ConcurrentModificationException 异常,从而产生fail-fast机制。

方案一:在遍历过程中所有涉及到改变modCount值得地方全部加上synchronized或者直接使用Collections.synchronizedList,这样就可以解决。但是不推荐,因为增删造成的同步锁可能会阻塞遍历操作。



方案二:使用CopyOnWriteArrayList来替换ArrayList。

CopyOnWriteArrayList所有可变操作(add、set 等等)都是通过对底层数组进行一次新的复制来实现的。

该类产生的开销比较大,但是在两种情况下,它非常适合使用。1:在不能或不想进行同步遍历,但又需要从并发线程中排除冲突时。2:当遍历操作的数量大大超过可变操作的数量时。



CopyOnWriterArrayList根本就不会产生ConcurrentModificationException异常,也就是它使用迭代器完全不会产生fail-fast机制。

public boolean add(E paramE) {  
        ReentrantLock  localReentrantLock = this.lock;  
        localReentrantLock.lock();  
        try {  
            Object[] arrayOfObject1 = getArray();  
            int i = arrayOfObject1.length;  
            Object[] arrayOfObject2 = Arrays.copyOf(arrayOfObject1, i + 1);  
            arrayOfObject2[i] = paramE;  
            setArray(arrayOfObject2);  
            int j = 1;  
            return j;  
        } finally {  
            localReentrantLock.unlock();  
        }  
    }  
  
      
    final void setArray(Object[] paramArrayOfObject) {  
        this.array = paramArrayOfObject;  
    }
分享到:
评论

相关推荐

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

    需要注意的是,这里使用`iterator.remove()`而不是`list.remove()`来删除元素,这可以避免并发修改异常。 ### 三、使用HashSet特性去除重复元素 这种方法利用了HashSet的特性,即HashSet不允许有重复的元素。将...

    java中关于集合的操作

    - **容量与大小**: `size()`返回集合元素数量,`ensureCapacity()`预先设定容量。 4. **集合转换**: - `toArray()`:将集合转换为数组。 - `copyOf()`:Java 8引入,用于安全地创建数组副本。 5. **集合操作**...

    java多线程并发及集合框架面试题

    面试中,Java 集合框架和多线程并发是常见的话题,因为它们是构建可扩展和健壮应用的基础。本题旨在考察候选人在实际并发场景下对 HashMap 和 ConcurrentHashMap 的理解和应用。 HashMap 和 ConcurrentHashMap 的...

    List.removeAll() 方法的性能效率

    这个方法是集合框架的一部分,它提供了高效的方式来进行元素的删除操作。本文将深入探讨`removeAll()`方法的性能效率,以及如何在实际应用中优化其使用。 首先,`removeAll()`方法的实现基于迭代器,这意味着它会...

    66丨迭代器模式(中):遍历集合的同时,为什么不能增删集合元素?1

    迭代器模式是一种设计模式,它的主要作用是在不暴露容器内部结构的情况下,提供一种遍历容器内元素的方法。这种模式使得代码解耦,提高了灵活性。在Java等编程语言中,迭代器通常通过`Iterator`接口来实现,允许用户...

    java集合框架全面进阶.pdf

    Iterator只能用于单向遍历,使用它的remove()方法可以从集合中移除元素。 6. **fail-fast机制**:这是集合框架中处理并发修改的一种机制。当集合在迭代过程中被修改,并且检测到这种修改时,迭代器会立即抛出...

    JAVA中常用的集合类型

    而 Vector 集合实现了对线程同步的支持,因此在多线程并发访问的应用环境下,该集合本身能够保证自身具有线程安全性。 Set 接口 Set 接口代表一个无序并且不允许元素重复存在的集合。Set 接口的实现类有 HashSet、...

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

    这个问题在单线程环境下不会出现,但在多线程并发场景下,如果多个线程同时修改一个集合,就可能导致`ConcurrentModificationException`。 标题中提到的“遍历并批量删除容器中元素”是引发此异常的一个典型操作。...

    Java list.remove( )方法注意事项

    下面将详细介绍`List.remove()`方法的两种用法及其注意事项。 首先,`remove(int index)`方法用于根据提供的索引从列表中移除一个元素。索引是从0开始的,所以`remove(0)`会删除列表的第一个元素,`remove(1)`会...

    Java集合 练习代码

    HashMap不是线程安全的,适用于高并发环境下的非同步访问。在练习代码中,你将看到如何创建HashMap,插入键值对,以及获取和更新键值对的方法。 此外,集合框架还包括其他的接口和实现类,如TreeSet、TreeMap等,...

    集合框架源码分析

    在多线程环境下,Java提供了`ConcurrentHashMap`、`CopyOnWriteArrayList`等并发安全的集合实现。这些类使用了高级并发策略,如分段锁或读写锁,以确保在并发环境下的正确性和性能。 8. **泛型(Generics)** ...

    java集合.docx

    **注意事项** 在使用集合时,确保了解所选集合类型的特点和适用场景,以及在遍历过程中对集合进行修改可能会导致的并发修改异常(CooncurrentModificationException)。如果在遍历过程中需要修改集合,推荐使用迭代器...

    集合框架学习笔记

    迭代器用于遍历集合中的元素,提供remove()方法删除元素。泛型则增强了类型安全性,避免了运行时类型转换异常,提高了代码可读性和复用性。 此外,Collection接口提供了addAll()、removeAll()和retainAll()等方法,...

    两个集合比较(新增、编辑、删除)

    要找出在第二个List中已被删除的元素,我们可以通过将第一个List的元素移除掉在第二个List中存在的元素来实现: ```java list1.removeAll(list2); ``` `list1`现在只包含在第二个List中被删除的元素。 4. **...

    阿里开发规范(集合与并发处理)

    **强制规定**:在 `subList` 场景中,需要注意对原始集合元素的增删操作,这些操作都可能导致子列表的遍历、增删产生 `ConcurrentModificationException` 异常。 **说明**:在使用 `subList` 方法时,对原始列表的...

    三歪教你学Java集合(1).pdf

    上述操作方法是集合框架中的核心操作,它们提供了对集合元素进行增加、检索和删除的能力。 7. 迭代器模式: 迭代器(Iterator)是Java集合框架中用于遍历集合的工具。它提供了一个通用的遍历接口,使得可以通过不同...

    Java集合框架详解

    在实际开发中,还需要关注线程安全问题,了解并发环境下如何正确使用并发集合,如ConcurrentHashMap和CopyOnWriteArrayList等。此外,深入学习集合框架的源码,可以进一步理解其内部实现机制,有助于编写更高效、更...

    Java concurrency集合之CopyOnWriteArraySet_动力节点Java学院整理

    10. `iterator()`: 获取一个按照添加顺序遍历集合元素的迭代器。 11. `remove(Object o)`: 删除指定元素。 12. `removeAll(Collection&lt;?&gt; c)`: 移除集合中与指定集合相同的元素。 13. `retainAll(Collection&lt;?&gt; c)`:...

    Java集合详解,详细讲解java的集合类

    然而,同步也意味着其性能可能低于非同步的ArrayList,特别是在并发访问较少的情况下。 4. Stack:Stack是Vector的一个子类,实现了LIFO(后进先出)栈的数据结构。它的操作主要是push和pop,以及peek查看栈顶元素...

    java集合资料整理

    - `next()`:返回集合中的下一个元素。 - `remove()`:移除迭代器中最近返回的那个元素。 通过使用`Iterator`,可以在遍历集合的同时安全地移除元素,而不会引发并发修改异常。 #### 五、总结 理解Java集合框架的...

Global site tag (gtag.js) - Google Analytics