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

2016-02-19 11:41 0 1 收藏

下面,图老师小编带您去了解一下java 集合并发操作出现的异常ConcurrentModificationException,生活就是不断的发现新事物,get新技能~

【 tulaoshi.com - 编程语言 】

如Java中的容器Map:
for(Person person : pList){
if(person.getGender()==Gender.MALE){
pList.remove(person); //不能在遍历期间进行 remove这个操作
}
}
Map在遍历时候通常 现获得其键值的集合Set,然后用迭代器Iterator来对Map进行遍历。
注意在遍历的过程中,只能对Map中的元素进行相应的处理,不能把Map元素增加或者把Map元素减少,也就是说,不能改变Map的size大小,就会出现异常(不能在遍历过程中修改删除或者增加map中的元素)
报出的异常为 java.util.ConcurrentModificationException 异常
public class ConcurrentModificationExceptionextends RuntimeException
当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection。通常在这些情况下,迭代的结果是不明确的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常。执行该操作的迭代器称为快速失败迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任意发生不确定行为的风险。
注意,此异常不会始终指出对象已经由不同 线程并发修改。如果单线程发出违反对象协定的方法调用序列,则该对象可能抛出此异常。例如,如果线程使用快速失败迭代器在 collection 上迭代时直接修改该 collection,则迭代器将抛出此异常。
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败操作会尽最大努力抛出 ConcurrentModificationException。因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法,正确做法是:ConcurrentModificationException 应该仅用于检测 bug。
当使用 fail-fast iterator 对 Collection 或 Map 进行迭代操作过程中尝试直接修改 Collection / Map 的内容时,即使是在单线程下运行, java.util.ConcurrentModificationException 异常也将被抛出。
  Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
  所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
  有意思的是如果你的 Collection / Map 对象实际只有一个元素的时候, ConcurrentModificationException 异常并不会被抛出。这也就是为什么在 javadoc 里面指出: it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

来源:https://www.tulaoshi.com/n/20160219/1598253.html

延伸阅读
标签: Web开发
代码如下: package cn.lang.any.listener; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class AmpList implements ServletContextListener,HttpSessionListener,HttpSessionAttributeListener { private ServletContext application=null; public void contextInitialized(ServletContextEvent...
技巧1:使用键盘的方向键移动对象时,按住【Shift】键不放,每次可以移动10个象素。 技巧2:使用【指针】工具移动对象时,按住【Shift】键不放,可以保证其水平或垂直移动。 技巧3:按住【Alt】键不放拖拽某个对象,即可对其进行复制。但是自动形状不能用这个操作,因为自动形状是一种组合状态,可以使用复制粘贴命令复制。 ...
我与无痛分娩亲密接触 听妈妈说过她生我的时候受尽了折磨,经历死去活来的宫缩痛。当时想做女人真是太不容易了。当我怀孕六个月时,我的一位朋友先一步采用了无痛分娩技术轻松地生下了宝宝。这对我来说,简直是个天大的喜讯,给我减了不少压力。 医生介绍说,人类的神经纤维可以分为感觉神经和运动神经,感受痛觉的神经比较小,用较低浓度的...
输入输出流 在Java中,我们把能够读取一个字节序列的对象称作一个输入流;而我们把够写一个字节序列称作一个输出流。它们分别由抽象类 InputStream和OutputStream类表示。因为面向字节的流不方便用来处理存储为Unicode(每个字符使用两个字节)的信息。所以Java 引入了用来处理Unicode字符的类层次,这些类派生自抽象类Reader...
1、不能在finally块中执行return,continue等语句,否则会把异常“吃掉”; 2、在try,catch中假如有return语句,则在执行return之前先执行finally块 请大家仔细看下面的例子: 以下是引用片段: public class TryTest {      public static void main(S...

经验教程

671

收藏

37
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部