java.util.ConcurrentModificationException 出现的原因和解决办法
来源:互联网 发布:破解解压密码的软件 编辑:程序博客网 时间:2024/05/18 03:18
用iterator遍历集合时碰到java.util.ConcurrentModificationException这个异常,
下面以List为例来解释为什么会报java.util.ConcurrentModificationException这个异常,代码如下:
public static void main(String[] args) { List<String> saveList=new ArrayList<>(); List<String> list=new ArrayList<>(); for (int j=1; j < 100; j++) { list.add(String.valueOf(j)); } Iterator<String> sss=list.iterator(); while (sss.hasNext()) { if ("50".equals(sss.next())) { list.remove("50"); } } }就是在遍历list的时候同时对list进行删除操作,就会报出java.util.ConcurrentModificationException,下面看一下java.util. AbstractList的内部类Itr的源码:
private class Itr implements Iterator<E> { /** * Index of element to be returned by subsequent call to next. */ int cursor = 0; /** * Index of element returned by most recent call to next or * previous. Reset to -1 if this element is deleted by a call * to remove. */ int lastRet = -1; /** * The modCount value that the iterator believes that the backing * List should have. If this expectation is violated, the iterator * has detected concurrent modification. */ int expectedModCount = modCount; public boolean hasNext() { return cursor != size(); } public E next() { checkForComodification(); //检测modCount和expectedModCount的值!! try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } public void remove() { if (lastRet == -1) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this.remove(lastRet); //执行remove的操作 if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount; //保证了modCount和expectedModCount的值的一致性,避免抛出ConcurrentModificationException异常 } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) //当modCount和expectedModCount值不相等时,则抛出ConcurrentModificationException异常 throw new ConcurrentModificationException(); } }我们可以发现,ArrayList的remove方法只是修改了modCount的值,并没有修改expectedModCount,导致modCount和expectedModCount的值的不一致性,当next()时则抛出ConcurrentModificationException异常
因此使用Iterator遍历集合时,不要改动被迭代的对象,可以使用 Iterator 本身的方法 remove() 来删除对象,Iterator.remove() 方法会在删除当前迭代对象的同时维护modCount和expectedModCount值的一致性。知道问题的原因就好办了。
这里总共提供3中方式处理这个问题:
1、新建一个saveList对象用于保存要删除的值,等遍历完后调用list的removeAll方法删除:
for(String list1 : list){ if("50".equals(list1)){ saveList.add("50"); } } list.removeAll(saveList);2、使用Iterator替代增强型for循环 ,Iterator.remove()方法保证了modCount和expectedModCount的值的一致性,避免抛出ConcurrentModificationException异常。
Iterator<String> sss=list.iterator(); while (sss.hasNext()) { if ("50".equals(sss.next())) { sss.remove(); } }以上俩种方式在单线程环境下不会有问题,但是在多线程并发执行的情况下还是会出现问题,所以就引入第三种方式:使用CopyOnWriteArrayList替代ArrayList:
public static void main(String[] args) { List<String> list=new CopyOnWriteArrayList<>(); for (int j=1; j < 100; j++) { list.add(String.valueOf(j)); } Iterator<String> sss=list.iterator(); while (sss.hasNext()) { if ("50".equals(sss.next())) { list.remove("50"); } } }
CopyOnWriteArrayList也是一个线程安全的ArrayList,其实现原理在于,每次add,remove等所有的操作都是重新创建一个新的数组,再把引用指向新的数组。
由于我用CopyOnWriteArrayList少,这里就不多讨论了,想了解可以看:Java并发编程:并发容器之CopyOnWriteArrayList
由于我用CopyOnWriteArrayList少,这里就不多讨论了,想了解可以看:Java并发编程:并发容器之CopyOnWriteArrayList
对于hashMap也有类似的情况,看如下代码:
public static void main(String[] args) { Map<String, String> map=new HashMap<>(); for (int i=1; i < 100; i++) { map.put(String.valueOf(i), "testMap"); } //将map中key的值都加上tf56前缀 for (String key : map.keySet()) { String value=map.get(key); map.remove(key); map.put("tf56" + key, value); } }执行结果同样会抛出:java.util.ConcurrentModificationException异常,解决的办法也是非常的简单:
用ConcurrentHashMap代替HashMap即可完美解决:
public static void main(String[] args) { Map<String, String> map=new ConcurrentHashMap<>(); for (int i=1; i < 100; i++) { map.put(String.valueOf(i), "testMap"); } //将map中key的值都加上tf56前缀 for (String key : map.keySet()) { String value=map.get(key); map.remove(key); map.put("tf56" + key, value); } }
阅读全文
0 0
- java.util.ConcurrentModificationException 出现的原因和解决办法
- java.util.ConcurrentModificationException 出现的原因和解决办法
- java.util.ConcurrentModificationException 出现的原因和解决办法
- java.util.ConcurrentModificationException 出现的原因和解决办法
- java.util.ConcurrentModificationException 出现的原因和解决办法
- java.util.ConcurrentModificationException 出现的原因和解决办法
- 出现 java.util.ConcurrentModificationException 时的解决办法
- 出现 java.util.ConcurrentModificationException 时的解决办法
- 出现 java.util.ConcurrentModificationException 时的解决办法
- java.util.ConcurrentModificationException产生原因及解决办法
- java.util.ConcurrentModificationException的解决办法
- java.util.ConcurrentModificationException的解决办法
- HashMap出现 java.util.ConcurrentModificationException 时的解决办法
- Java中出现java.util.ConcurrentModificationException的原理探究和解决办法
- java.util.ConcurrentModificationException原因
- java.util.ConcurrentModificationException原因
- java.util.ConcurrentModificationException原因
- 【ConcurrentModificationException】java.util.ConcurrentModificationException 解决办法
- 解决Failed to load class "org.slf4j.impl.StaticLoggerBinder"问题
- 软件推荐:傲梅科技分区助手
- 阿里云部署redis服务器,以及远程访问
- Struts Ognl表达式语言几个符号 % $ #
- 正则判断是手机号码
- java.util.ConcurrentModificationException 出现的原因和解决办法
- 深入理解Java并发之synchronized实现原理
- 第一章 Zookeeper 介绍
- ef_分页查询
- python教程之一-----使用Python解释器
- 树形DP入门(一)『ツリーとしては』
- 极乐技术周报(第二十四期)
- 快速排序
- Ubuntu中Vim插件NERDTree的安装