ConcurrentModificationException in Java
The ConcurrentModificationException occurs when an object is tried to be modified concurrently when it is not permissible. This exception usually comes when one is working with Java Collection classes.
For Example : It is not permissible for a thread to modify a Collection when some other thread is iterating over it. This is because the result of the iteration becomes undefined with it. Some implementation of the Iterator class throws this exception, including all those general-purpose implementations of Iterator which are provided by the JRE. Iterators which do this are called fail-fast as they throw the exception quickly as soon as they encounter such situation rather than facing undetermined behavior of the collection any time in the future.
It is not mandatory that this exception will be thrown only when some other thread tries to modify a Collection object. It can also happen if a single thread has some methods called which are trying to violate the contract of the object. This may happen when a thread is trying to modify the Collection object while it is being iterated by some fail-fast iterator, the iterator will throw the exception.
Let’s see the concurrent modification exception scenario with an example:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class ConcurrentModificationExceptionExample {
public static void main(String args[]) {
List<String> myList = new ArrayList<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(value);
}
Map<String, String> myMap = new HashMap<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("2")) {
myMap.put("1", "4");
// myMap.put("4", "4");
}
}
}
}
Above program will throw java.util.ConcurrentModificationException
when executed, as shown in below console logs.
From the output stack trace, it’s clear that the concurrent modification exception is thrown when we call iterator next()
function.
If you are wondering how Iterator checks for the modification, it’s implementation is present in the AbstractList class, where an int variable modCount is defined. The modCount provides the number of times list size has been changed. The modCount value is used in every next() call to check for any modifications in a function checkForComodification()
.
Now, comment out the list part and run the program again. You will see that there is no ConcurrentModificationException being thrown now.
Output: 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. The output may be different in your system because HashMap keyset is not ordered like a List. If you will uncomment the statement where I am adding a new key-value in the HashMap, it will cause Concurrent Modification Exception.
To Avoid ConcurrentModificationException in multi-threaded environment
- 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.
- 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.
- If you are using JDK1.5 or higher then you can use ConcurrentHashMap or SynchronizedMap and CopyOnWriteArrayList classes. This is the recommended approach to avoid concurrent modification exception.
- One more solution is here, you can simple copy all keys in List and iterate on that list of keys.
Single Thread Environment : 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 an Iterator.
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. 🙂
One More Thing: You will get ConcurrentModificationException if you will try to modify the structure of the original list with subList.
Happy Blogging !