java.util.ConcurrentModificationException is a very common exception when working with java collection classes. Java Collection classes are fail-fast, which means if the Collection will be changed while some thread is traversing over it using iterator, the iterator.next() will throw ConcurrentModificationException. Concurrent modification exception can come in case of multithreaded as well as single threaded java programming environment.

java.util.ConcurrentModificationException

Let’s see the concurrent modification exception scenario with an example.


Copy
package com.journaldev.ConcurrentModificationException; import java.util.ArrayList;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map; public class ConcurrentModificationExceptionExample {
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span>(<span class="hljs-params">String args[]</span>) </span>{
List&lt;String&gt; myList = <span class="hljs-keyword">new</span> ArrayList&lt;String&gt;(); myList.<span class="hljs-keyword">add</span>(<span class="hljs-string">"1"</span>);
myList.<span class="hljs-keyword">add</span>(<span class="hljs-string">"2"</span>);
myList.<span class="hljs-keyword">add</span>(<span class="hljs-string">"3"</span>);
myList.<span class="hljs-keyword">add</span>(<span class="hljs-string">"4"</span>);
myList.<span class="hljs-keyword">add</span>(<span class="hljs-string">"5"</span>); Iterator&lt;String&gt; it = myList.iterator();
<span class="hljs-keyword">while</span> (it.hasNext()) {
String <span class="hljs-keyword">value</span> = it.next();
System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"List Value:"</span> + <span class="hljs-keyword">value</span>);
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">value</span>.<span class="hljs-keyword">equals</span>(<span class="hljs-string">"3"</span>))
myList.<span class="hljs-keyword">remove</span>(<span class="hljs-keyword">value</span>);
} Map&lt;String, String&gt; myMap = <span class="hljs-keyword">new</span> HashMap&lt;String, String&gt;();
myMap.put(<span class="hljs-string">"1"</span>, <span class="hljs-string">"1"</span>);
myMap.put(<span class="hljs-string">"2"</span>, <span class="hljs-string">"2"</span>);
myMap.put(<span class="hljs-string">"3"</span>, <span class="hljs-string">"3"</span>); Iterator&lt;String&gt; it1 = myMap.keySet().iterator();
<span class="hljs-keyword">while</span> (it1.hasNext()) {
String key = it1.next();
System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"Map Value:"</span> + myMap.<span class="hljs-keyword">get</span>(key));
<span class="hljs-keyword">if</span> (key.<span class="hljs-keyword">equals</span>(<span class="hljs-string">"2"</span>)) {
myMap.put(<span class="hljs-string">"1"</span>, <span class="hljs-string">"4"</span>);
<span class="hljs-comment">// myMap.put("4", "4");</span>
}
} }

}

Above program will throw java.util.ConcurrentModificationException when executed, as shown in below console logs.


Copy
List Value:1
List Value:2
List Value:3
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:937)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:891)
at com.journaldev.ConcurrentModificationException.ConcurrentModificationExceptionExample.main(ConcurrentModificationExceptionExample.java:22)

From the output stack trace, its clear that the concurrent modification exception is coming when we call iterator next() function. If you are wondering how Iterator checks for the modification, its implementation is present in AbstractList class where an int variable modCount is defined. modCount provides the number of times list size has been changed. modCount value is used in every next() call to check for any modifications in a function checkForComodification().

Now comment the list part and run the program again. You will see that there is no ConcurrentModificationException being thrown now.

Output will be:


Copy
Map Value:3
Map Value:2
Map Value:4

Since we are updating the existing key value in the myMap, its size has not been changed and we are not getting ConcurrentModificationException. Note that the output may differ in your system because HashMap keyset is not ordered like list. If you will uncomment the statement where I am adding a new key-value in the HashMap, it will cause ConcurrentModificationException.

To Avoid ConcurrentModificationException in multi-threaded environment

  1. You can convert the list to an array and then iterate on the array. This approach works well for small or medium size list but if the list is large then it will affect the performance a lot.
  2. You can lock the list while iterating by putting it in a synchronized block. This approach is not recommended because it will cease the benefits of multithreading.
  3. If you are using JDK1.5 or higher then you can use ConcurrentHashMap and CopyOnWriteArrayList classes. This is the recommended approach to avoid concurrent modification exception.

To Avoid ConcurrentModificationException in single-threaded environment

You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.

Let us run an example using Concurrent Collection classes:


Copy
package com.journaldev.ConcurrentModificationException; import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList; public class AvoidConcurrentModificationException { public static void main(String[] args) { List<String> myList = new CopyOnWriteArrayList<String>(); myList.add("1");
myList.add("2");
myList.add("3");
myList.add("4");
myList.add("5"); Iterator<String> it = myList.iterator();
while (it.hasNext()) {
String value = it.next();
System.out.println("List Value:" + value);
if (value.equals("3")) {
myList.remove("4");
myList.add("6");
myList.add("7");
}
}
System.out.println("List Size:" + myList.size()); Map<String, String> myMap = new ConcurrentHashMap<String, String>();
myMap.put("1", "1");
myMap.put("2", "2");
myMap.put("3", "3"); Iterator<String> it1 = myMap.keySet().iterator();
while (it1.hasNext()) {
String key = it1.next();
System.out.println("Map Value:" + myMap.get(key));
if (key.equals("1")) {
myMap.remove("3");
myMap.put("4", "4");
myMap.put("5", "5");
}
} System.out.println("Map Size:" + myMap.size());
} }

Output of above program is shown below. You can see that there is no ConcurrentModificationException being thrown by the program.



Copy
List Value:1
List Value:2
List Value:3
List Value:4
List Value:5
List Size:6
Map Value:1
Map Value:2
Map Value:4
Map Value:5
Map Size:4

From the above example its clear that:

  1. Concurrent Collection classes can be modified safely, they will not throw ConcurrentModificationException.
  2. In case of CopyOnWriteArrayList, iterator doesn’t accommodate the changes in the list and works on the original list.
  3. In case of ConcurrentHashMap, the behaviour is not always the same.

    For condition:

    
    
    Copy
    if(key.equals("1")){
    myMap.remove("3");}

    Output is:

    
    
    Copy
    Map Value:1
    Map Value:null
    Map Value:4
    Map Value:2
    Map Size:4

    It is taking the new object added with key “4” but not the next added object with key “5”.

    Now if I change the condition to below.

    
    
    Copy
    if(key.equals("3")){
    myMap.remove("2");}

    Output is:

    
    
    Copy
    Map Value:1
    Map Value:3
    Map Value:null
    Map Size:4

    In this case its not considering the new added objects.

    So if you are using ConcurrentHashMap then avoid adding new objects as it can be processed depending on the keyset. Note that the same program can print different values in your system because HashMap keyset is not ordered.

Use for loop to avoid java.util.ConcurrentModificationException

If you are working on single-threaded environment and want your code to take care of the extra added objects in the list then you can do so using for loop rather than iterator.


Copy
for(int i = 0; i<myList.size(); i++){
System.out.println(myList.get(i));
if(myList.get(i).equals("3")){
myList.remove(i);
i--;
myList.add("6");
}
}

Note that I am decreasing the counter because I am removing the same object, if you have to remove the next or further far object then you don’t need to decrease the counter. Try it yourself.

java.util.ConcurrentModificationException(如何避免ConcurrentModificationException)的更多相关文章

  1. java.util.ConcurrentModificationException 解决办法(转载)

    今天在项目的中有一个需求,需要在一个Set类型的集合中删除满足条件的对象,这时想当然地想到直接调用Set的remove(Object o)方法将指定的对象删除即可,测试代码:   public cla ...

  2. java.util.ConcurrentModificationException --map

    key:3-key key:/v1.02-key Exception in thread "main" java.util.ConcurrentModificationExcept ...

  3. 偶遇到 java.util.ConcurrentModificationException 的异常

    今天在调试程序 遇到了如此问题 贴上代码来看看稍后分析 List<String> list = null;boolean isUpdate = false;try { list = JSO ...

  4. 对ArrayList操作时报错java.util.ConcurrentModificationException null

    用iterator遍历集合时要注意的地方:不可以对iterator相关的地方做添加或删除操作.否则会报java.util.ConcurrentModificationException 例如如下代码: ...

  5. LinkedList - java.util.ConcurrentModificationException

    package com.test.io; import java.io.BufferedReader; import java.io.FileNotFoundException; import jav ...

  6. java.util.ConcurrentModificationException 解决办法

    在使用iterator.hasNext()操作迭代器的时候,如果此时迭代的对象发生改变,比如插入了新数据,或者有数据被删除. 则使用会报以下异常:Java.util.ConcurrentModific ...

  7. Iterator之java.util.ConcurrentModificationException

    在运行以下代码时,会报java.util.ConcurrentModificationException异常, public class Demo { public static void main( ...

  8. java.util.ConcurrentModificationException 解决办法(转)

    今天在项目的中有一个需求,需要在一个Set类型的集合中删除满足条件的对象,这时想当然地想到直接调用Set的remove(Object o)方法将指定的对象删除即可,测试代码:   public cla ...

  9. java集合--java.util.ConcurrentModificationException异常

    ConcurrentModificationException 异常:并发修改异常,当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常.一个线程对collection集合迭代,另一个线程对Co ...

  10. list删除操作 java.util.ConcurrentModificationException

    首先大家先看一段代码: public static void main(String[] args) { List<String> listStr = new ArrayList<S ...

随机推荐

  1. TaoCode-淘宝的SVN开源托管平台

    无意中发现的..试用了一下,感觉还不错, 简单说一下怎样使用: 进入 http://code.taobao.org/project/explore/ 注冊完后依据提示新建项目,然后在本地随便新建一个文 ...

  2. Dynamics CRM 2015/2016 Web API:Unbound Custom Action 和 Bound Custom Action

    今天我们再来看看Bound/Unbound Custom Action吧,什么是Custom Action?不知道的小伙伴们就out了,Dynamics CRM 2013就有了这个功能啦.和WhoAm ...

  3. vim 基础学习之插入模式

    插入模式1.字符编码,插入特殊字符 <C-v>{3位} 如,你想输入A,你可以在输入模式下<C-v>065(必须是3位) <C-v>u{4位} 如,你想输入¿,你可 ...

  4. kali之Nmap (Network Mapper(网络映射器)

    Nmap是主机扫描工具,他的图形化界面是Zenmap,分布式框架为Dnamp. Nmap可以完成以下任务: 主机探测 端口扫描 版本检测 系统检测 支持探测脚本的编写 Nmap在实际中应用场合如下: ...

  5. yum---rpm软件包管理器

    yum命令是在Fedora和RedHat以及SUSE中基于rpm的软件包管理器,它可以使系统管理人员交互和自动化地更细与管理RPM软件包,能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖性 ...

  6. C# Unable to load DLL 'WzCanDll.dll':找不到指定的模块

    一.打开app无法加载DLL 我用C++编写的DLL,然后用C#写的界面APP,在自己的电脑上打开没有问题,放在其它电脑上就出现无法加载DLL库的问题,一连接APP就会出现问题,如下图所示: 二.解决 ...

  7. 图片工具GraphicsMagick的安装配置与基本使用

    本文使用GraphicsMagick的版本为1.3.18 (Released March 9, 2013). 1.简介 GraphicsMagick是一个短小精悍的的图片处理工具和库集合.对于Java ...

  8. C++怎么访问私有变量和函数

    用指针呀,了解C++内存结构的话. 1. 对于私有成员变量,可以用指针来访问. 2. 对于虚函数,也可以用指针来访问. 3. 另外,对于私有成员,如果摸不准地址构造,可以先构造一个结构相似的类,然后增 ...

  9. Flume的可管理性

    Flume的可管理性  所有agent和Collector由master统一管理,这使得系统便于维护. 多master情况,Flume利用 ZooKeeper和gossip,保证动态配置数据的一致性. ...

  10. 深入理解Java内存模型--转载

    原文地址:http://www.infoq.com/cn/articles/java-memory-model-1 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之 ...