原文网址: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. codevs 2822爱在心中

    不想吐槽题目.... /* K bulabula 算法(好像用哪个T bulabula更简单 然而我并不会 - -) 丑陋的处理cnt: Printf时 cnt中 ans[i][0]==1 的删掉 然 ...

  2. python爬虫scrapy的Selectors参考文档

    http://doc.scrapy.org/en/1.0/topics/selectors.html#topics-selectors-htmlcode

  3. CSS Pseudo-Element Selectors伪对象选择符

    一: CSS3将伪对象选择符(Pseudo-Element Selectors)前面的单个冒号(:)修改为双冒号(::)用以区别伪类选择符(Pseudo-Classes Selectors),但以前的 ...

  4. HTML5 文件域+FileReader 分段读取文件并上传(七)-WebSocket

    一.单文件上传实例 HTML: <div class="container"> <div class="panel panel-default" ...

  5. 测试Kettle在增量更新的时候是否支持级联——不支持(基于mysql)

    由于LZ很像整理一下如何使用Kettle对一张表进行增量更新的时候, 同时实现对数据库中的其他表也可以实现相关的更新操作. 第一种方法想使用触发器,即在相应的hop之间添加SQL脚本step然后在st ...

  6. java中怎么进行字符串替换?

    String str = "test.doc"; String newStr = str.replaceAll("doc","html");

  7. UILabel的高度自适应

    _content = [UILabel new]; _content.text = @"日落时分,沏上一杯山茶,听一曲意境空远的<禅>,心神随此天籁,沉溺于玄妙的幻境里.仿佛我就 ...

  8. SpringMVC4+thymeleaf3的一个简单实例(篇四:form表单数据验证)

    关于表单数据验证有很多中方法,这里我仅介绍JSR303注解验证.JSR303仅仅是一个规范,这里我们要用到它的一个实现:hibernate-validator. 注意在spring的配置文件sprin ...

  9. 【POJ3580】【splay版】SuperMemo

    Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant i ...

  10. Perl中级第四章课后习题

    1.下列表达式各表示什么不同的含义: $ginger->[2][1] ${$ginger[2]}[1] $ginger->[2]->[1] ${$ginger->[2]}[1] ...