关于ConcurrentModificationException异常

Sat Oct 11 18:04:32 CST 2008发表于搜斧SearchFull
关于 ConcurrentModificationException异常

在Java API里已经解释了这个 ConcurrentModificationException异常的来历:

当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线程修改该 Collection。通常在这些情况下,迭代的结果是不明确的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常。执行该操作的迭代器称为 快速失败 迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任意发生不确定行为的风险。

注意,此异常不会始终指出对象已经由 不同 线程并发修改。如果单线程发出违反对象协定的方法调用序列,则该对象可能抛出此异常。例如,如果线程使用快速失败迭代器在 collection 上迭代时直接修改该 collection,则迭代器将抛出此异常。

注意,迭代器的fail-fast快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败操作会尽最大努力抛出 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.

下面的代码没有问题:

  1. import java.util.*;  
  2.   
  3. public class TryIteratorRemove {  
  4.     public static void main(String [] args){  
  5.         Collection<String> myCollection = new ArrayList<String>(10);  
  6.           
  7.         myCollection.add("123");  
  8.         myCollection.add("456");  
  9.         myCollection.add("789");  
  10.           
  11.         int i=0;  
  12.           
  13.         for(Iterator it = myCollection.iterator();it.hasNext();) {  
  14.             String myObject = (String)it.next();  
  15.             System.out.println(myObject);  
  16.               
  17.             i++;  
  18.   
  19.             if(i==1){  
  20.                 //myCollection.remove(myObject);  //这行代码有问题,会抛出 ConcurrentModificationException
  21.                 it.remove();  
  22.             }  
  23.         }  
  24.   
  25.         System.out.println("After remove,the size of myCollection is: " +  
  26.                        myCollection.size()+" \n and its content is: ");  
  27.   
  28.         for(String s : myCollection){  
  29.             System.out.println(s);  
  30.         }  
  31.     }  


 
阅读全文...
 
本站相关内容:(RSS)

请大家帮忙 关于异常:org.springframework.transaction.TransactionSystemException

     摘要: 最近在项目中间遇到一个棘手的问题,希望有经验的朋友能帮帮小弟,感激不尽。 具体问题是:在工程部署到tomcat,然后启动tamcat,登录工程,无任何问题,但是问题出在大概一个小时以后,重新访问工程,登录时抛出如下异常:  1Exception Type: org.springframework.transaction.TransactionSystemExc...   阅读全文

小木 2007-12-15 11:54 发表评论

关于oracle'流已被关闭'异常

关于oracle'流已被关闭'异常 05月 13th, 2008 这两天被oracle的’流已被关闭’异常弄晕了头,网上找的也尽是提出这个问题但没有一个能解决或者说明原因的,大多数出在hibernate的应用,或者字段类型为long的情况下,一般的说法是第一个get必须取long数据类型,而且一个表中只能存在一个long字段类型(这种说法是错误的,其实单独写个类测试就会发现,oracle不会有这些问题,不论几个long类型field或是get的顺序都没问题),其实放到实际应用中,并不可能和单个测试类那样简单,可能存在了一个connection对象创建多个statement,即使创建后的statement和resultset用完关闭后,仍然会有这个问题产生,我抛出此异常的情况是第一个取long类型字段正确(用getLong),但是之后再取long类型时(是存储的文本类型,用getString)就会有’流已被关闭’的异常了,我的临时解决办法是再创建个新的connection对象创建statement和resultset就ok了,因为我先前用了一个connection对象创建了其它的s

关于Asp.net ajax下的异常处理

最近做一个项目时,大量应用了Asp.net ajax,由于在UpdatePanel这种异步更新模式下,后台处理时所发生的异常并不会导致客户端的界面发生变化,而是直接以alert的方式弹出异常信息,所以我在后台检测到不符合要求的输入之类的情况下,就直接把错误提示信息throw一下就好了。但现在发现问题了,就是这样一来,如何处理其它的未处理异常?

北海港(000582)关于股票异常波动及复牌的公告 - 新浪网


北海港(000582)关于股票异常波动及复牌的公告
新浪网 - 36分钟前
本公司及董事会保证信息披露内容的真实、准确、完整,没有虚假记载、误导性陈述或重大遗漏。 自2007年11月1日至5日,我公司股票(证券名称:北海港,代码:000582)交易价格连续三个交易日内日收盘价格涨幅偏离值累计达到20%。 我公司对是否有应披露而未披露信息事项函询了公司第一大股东北海市机场投资管理有限责任公司、第二大股东北海市 ...
北海港:股票异常波动及复牌 和讯
关注董事会秘书 国务院国有资产监督管理委员会
6条相关资讯
互联网相关内容:
请大家帮忙 关于异常:org.springframework.transaction.TransactionSystemException (2007年12月15日)
关于oracle'流已被关闭'异常 (2008年05月13日)
关于Asp.net ajax下的异常处理 (2008年06月20日)
北海港(000582)关于股票异常波动及复牌的公告 - 新浪网 (2007年11月25日)
甘肃荣华实业(集团)股份有限公司关于股票交易异常波动的公告 (2008年01月29日)
沈阳商业城股份有限公司董事会关于股票交易异常波动的公告 (2008年02月24日)
Java ConcurrentModificationException (2008年04月18日)
异常导致的异常 (2007年11月11日)