博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java.util.ConcurrentModificationException异常
阅读量:5805 次
发布时间:2019-06-18

本文共 4408 字,大约阅读时间需要 14 分钟。

hot3.png

原文地址:ConcurrentModificationException异常解决办法作者:心灵征途 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() + " entries left after iterator.");   34          pTmpKeys = null;   35      }   36      public static void main(String[] args) throws Exception{   38          MyTest.init();   39          MyTest.clear();   40      }   41  }

转载于:https://my.oschina.net/array2013/blog/177122

你可能感兴趣的文章
测试人员的GitHub
查看>>
Spring Web Services 3.0.4.RELEASE和2.4.3.RELEASE发布
查看>>
有关GitHub仓库分支的几个问题
查看>>
无服务器计算的黑暗面:程序移植没那么容易
查看>>
云原生的浪潮下,为什么运维人员适合学习Go语言?
查看>>
Webpack入门教程三十
查看>>
EAServer 6.1 .NET Client Support
查看>>
锐捷交换机密码恢复(1)
查看>>
Kali linux virtualbox rc=1908 错误解决办法
查看>>
Erlang学习总结之Erlang语法中的逗号(,)、分号(;),句号(.)的正确用法...
查看>>
linux软件包管理之三(源代码安装)
查看>>
数据库三范式是什么?
查看>>
[转载]设置Ubuntu自动连接无线,无须再输入密钥环和无线密码
查看>>
九叔Xen App测试报告
查看>>
Apache配置
查看>>
Ext gridPanel 单元格数据的渲染
查看>>
Android SDK 的下载代理
查看>>
Method Swizzling对Method的要求
查看>>
佛祖保佑,永不宕机
查看>>
四、配置开机自动启动Nginx + PHP【LNMP安装 】
查看>>