Exception in thread ... java.util.ConcurrentModificationException
at java.util.Hashtable$Enumerator.next(Unknown Source)
at ...
A quick look at the API documentation of ConcurrentModificationException says:
"This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible. For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it..."Now this may not be very useful for newbies. They may be left wondering about multi-threading, concurrent access etc. Given below is a sample code which is single threaded, yet, it fails with ConcurrentModifcationAccess. In this code I am trying to remove keys that end with digit "5" from a Map:
public class MapTest {
public static void main(String[] args) {
//create a sample Map
Map<String, String> map = new Hashtable<String,String>();
map.put("key1", "value100");
map.put("key2", "value200");
map.put("key3", "value300");
map.put("key4", "value400");
map.put("key5", "value500");
map.put("key55", "value550");
map.put("key6", "value600");
System.out.println("mappings before: "+map);
//retrieve the set of Keys in the map
Set<String> keySet = map.keySet();
//iterate over keys and remove
// those which ends with "5"
for(String key : keySet) {
if(key.endsWith("5" )) {
keySet.remove(key);
}
}
System.out.println("mappings after: "+map);
}
}
When you run this code it will throw concurrent modification exception. Now try the following sample. Changed code is highlighted.
This code runs fine. Why?
public class MapTest {
public static void main(String[] args) {
//create a sample Map
Map<String, String> map = new Hashtable<String,String>();
map.put("key1", "value100");
map.put("key2", "value200");
map.put("key3", "value300");
map.put("key4", "value400");
map.put("key5", "value500");
map.put("key55", "value550");
map.put("key6", "value600");
System.out.println("mappings before: "+map);
//retrieve the set of Keys in the map
Iterator<String> keySetItr = map.keySet().iterator();
while( keySetItr.hasNext()) {
String key = keySetItr.next();
if(key.endsWith("5" )) {
keySetItr.remove();
}
}
System.out.println("mappings after: "+map);
}
}
The evil is in the code:
for(String key : keySet) {
...
keySet.remove(key);
The for(...) actually opens an iterator internally and when we remove the key from KeySet this iterator logic breaks, throwing the ConcurrentModificationException. To avoid this one should use the second example given above, where same Iterator (keySetItr) is used both for iteration and removing the keys.
12 comments:
good tip... thank you!
nice info!
That was driving me mad! Thanks for the solution mate!
Great tip man. More power!
Thank you very much. This was such a difficult to understand bug.. such as elegant solution though, use the given remove feature in the iterator instead! Of course... duh !!
I have another question here.
If I have multi threaded application and one thread synchronized on the map and then open an iterator while other thread trying to modify the map (this thread is not synchronized), will we get the same error ?
Actually I am getting this error in this scenario and wondering how it is possible ?
Excellent! Gracias amigo
I always wondered how to get around this Exception. Thanks a lot!
Thanks a lot, you just saved my morning :)
really useful info! thank you!!
nice tip. Thanks much.
Che Dio ti benedica!
Dio benu vin! DANKON
God bless you
Post a Comment