原文网址:http://blog.sina.com.cn/s/blog_465bcfba01000ds7.html

1月30日
java.util.ConcurrentModificationException异常(转)
1、

今天在写一个带缓存功能的访问代理程序时出现了java.util.ConcurrentModificationException异常, 因为该异常是非捕获型异常而且很少见,所以费了些时间才找到问题所在,原来在通过Iterator进行遍历的时候,如果直接对HashMap进行操作后,再继续用之前的Iterator进行遍历就会出现这个异常,表示其HashMap已经被修改。

源程序代码片段如下:caches为一个HashMap对象

String sameKeyPart = accesserClassName + "@" + methodName + "@" + parameterKeyString + "@";
      Iterator keys = caches.keySet().iterator();
      String key = null;
      while (keys.hasNext()) ...{
        key = (String) keys.next();
        if (key.startsWith(sameKeyPart)) ...{
          caches.remove(key);
        }
      }

解决办法为通过其相应的Iterator进行删除就可以了,修改后代码片段如下:

String sameKeyPart = accesserClassName + "@" + methodName + "@" + parameterKeyString + "@";
      Iterator keys = caches.keySet().iterator();
      String key = null;
      while (keys.hasNext()) ...{
        key = (String) keys.next();
        if (key.startsWith(sameKeyPart)) ...{
          keys.remove();
        }
      }

2、

撰写多线程代码时,你遇到过多少次下面的提示:
Exception in thread "main" java.util.ConcurrentModificationException

这个异常产生的原因有几个。一是直接对集合调用删除操作而不是在枚举器上。二是不同的线程试图对集合进行增删操作的时候。

这个解决办法的第一步就是同步代码,使得你在枚举的时候其它的线程不能增删记录。但是如果每个枚举过程要进行复杂的计算或者是数据库访问的一部分的话,这个同步就会导致可怕的后果。为了减少负面影响,可以拷贝一个只读的枚举器,去掉同步,然后采用下列代码所示的方法:

private List list;
  public void add(Object obj) {
  synchronized(list) {
  list.add(obj);
  }
  }
  public void perform( ) {
  Iterator iterator = null;
  synchronized(list) {
  iterator = new CopiedIterator(list.iterator( ));
  }
  while(iterator.hasNext( )) {
  // perform resource or cpu hungry work
  }
  }
重要的是记住,CopiedIterator不是一个克隆,只是一个只读的拷贝,所以它并没有保持原有的全部功能。最重要的是,不能再调用CopiedIterator.remove方法了。CopiedIterator.remove的实现如下:

public class CopiedIterator implements Iterator {
  private Iterator iterator = null;
  public CopiedIterator(Iterator itr) {
  LinkedList list = new LinkedList( );
  while(itr.hasNext( )) {
  list.add(itr.next( ));
  }
  this.iterator = list.iterator( );
  }
  public boolean hasNext( ) {
  return this.iterator.hasNext( );
  }
  public void remove( ) {
  throw new UnsupportedOperationException("This is a read-only iterator.
  ");
  }
  public Object next( ) {
  return this.iterator.next( );
  }
  }
枚举器的只读拷贝将用在同步状态上的时间减少到最小,因此可以增强全局的效率。

3、

当使用 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 final class MyTest   
4  {   
5      private static HashMap p_mapList = new HashMap(2);   
6      private MyTest(){}   
7      public static void init(){   
8          // If only there are more than one element in Map,    
9          // the ConcurrentModificationException will not be   
10          // thrown.   
11          p_mapList.put(new String("hello"),new String("world"));   
12          p_mapList.put(new String("goto"),new String("hell"));   
13      }   
14      public static void clear() throws Exception{   
15          Iterator pTmpKeys = null;   
16          Long pTmpKeyLong;   
17          pTmpKeys = p_mapList.keySet().iterator();   
18          String pCurKey = null;   
19          String pCurObj = null;   
20          while(pTmpKeys.hasNext()){   
21              pCurKey = (String) pTmpKeys.next();   
22              pCurObj = (String) p_mapList.get(pCurKey);   
23    
24              p_mapList.put(pCurKey,null);   
25              // You can not remove element in Map object directly.   
26              //p_mapList.remove(pCurKey);   
27              // But you can remove current element by iterator itself.   
28              pTmpKeys.remove();   
29    
30              System.out.println(pCurKey + " removed.");   
31          }   
32          System.out.println(p_mapList.size() +    
33                              " entries left after iterator.");   
34          pTmpKeys = null;   
35      }   
36      public static void main(String[] args)   
37                                  throws Exception{   
38          MyTest.init();   
39          MyTest.clear();   
40      }   
41  }

自己的操作:用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

【转】ConcurrentModificationException异常解决办法 --不错的更多相关文章

  1. ConcurrentModificationException异常解决办法

    今天在写一个带缓存功能的访问代理程序时出现了java.util.ConcurrentModificationException异常,因为该异常是非捕获型异常而且很少见,所以费了些时间才找到问题所在,原 ...

  2. java.util.ConcurrentModificationException的解决办法

    今天在使用iterator.hasNext()操作迭代器的时候,当迭代的对象发生改变,比如插入了新数据,或者有数据被删除. 编译器报出了以下异常: Exception in thread " ...

  3. redis 异常解决办法

    redis 异常解决办法 26069:M 08 Aug 17:06:58.858 # WARNING: The TCP backlog setting of 511 cannot be enforce ...

  4. ClientAbortException 异常解决办法

    http://blog.sina.com.cn/s/blog_43eb83b90102ds8w.html ClientAbortException 异常解决办法 当我们用Servlet导出图片,或用J ...

  5. Attribute name invalid for tag form according to TLD异常解决办法_gaigai_百度空间

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  6. Android HttpURLConnection.connect找不到源 HttpURLConnection连接失败 HttpURLConnection.connect IO异常 解决办法

    Android HttpURLConnection.connect找不到源  HttpURLConnection连接失败 HttpURLConnection.connect IO异常 解决办法 以下代 ...

  7. org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session异常解决办法

    org.hibernate.NonUniqueObjectException: a different object with the same identifier value was alread ...

  8. java启动RabbitMQ消息报异常解决办法

    启动SpringCloud微服务,RabbitMQ报如下异常: 2019-08-12 18:15:49.543 ERROR 53096 --- [68.252.131:5672] o.s.a.r.c. ...

  9. ArchLinux——使用WINE-TIM头像异常解决办法

    ArchLinux--使用WINE-TIM头像异常解决办法 当使用WINE-TIM头像图片加载异常时,执行以下命令 sudo sysctl -w net.ipv6.conf.all.disable_i ...

随机推荐

  1. Marketplace Client- Download

    Marketplace是Java平台被广泛使用的IDE(集成开发环境)Eclipse的软件商店.上面有个有种牛X的插件,可根据自己需要下载. Eclipse Marketplace官网地址:http: ...

  2. Linux写配置HDF5的python包h5py

    闲言碎语不讲,直接进入正题.Python在科学计算的应用越来越丰度,而hdf(5)数据的应用也非常广泛.python提供了h5py包供开发者处理数据(http://www.h5py.org/).在wi ...

  3. 关于禁止ViewPager预加载问题【转】

    转自:http://blog.csdn.net/qq_21898059/article/details/51453938#comments 我最近上班又遇到一个小难题了,就是如题所述:ViewPage ...

  4. My-sql #1045 - Access denied for user 'root'@'localhost' (using password: NO)

    当你重装数据库后出现这个问题的时候,不要着急,首先你要去你的确定你的数据库已经成功的把服务开启了, 然后确定你的密码和账户,IP都确认的情况下, 去寻找config.inc.php 这个文件,根据配置 ...

  5. siege安装和使用

    siege(支持http.https).多url. 下载地址:http://www.joedog.org/index/siege-home Cent os系统: 1)./configure 2)mak ...

  6. TreeView checkbox

    C# TreeView checkbox 联动打勾 #region 将树的checkbox选中 private void setNodeTrue(Node selNode) { Node node = ...

  7. opencar二次开发常用代码

    <?php //创建Registry对象 //注册所有公共类 //创建Front类对象,作为请求分发器(Dispatcher) //根据用户请求(url)创建控制器对象及其动作. // 在Fro ...

  8. PropertyPlaceholderConfigurer的用法(使用spring提供的类读取数据库配置信息.properties)

    http://www.cnblogs.com/wanggd/archive/2013/07/04/3172042.html(写的很好)

  9. C语言字符串库函数的实现

    1.strlen(字符串的长度) size_t Strlen(const char* str) { assert(str); ;; ++i) { if (str[i] == '\0') return ...

  10. css3基础教程十三征服CSS3选择器

    :enabled选择器 在Web的表单中,有些表单元素有可用(“:enabled”)和不可用(“:disabled”)状态,比如输入框,密码框,复选框等.在默认情况之下,这些表单元素都处在可用状态.那 ...