Code looks like this: The maps being used here are Guava maps
private Map<SomeObject, SomeOtherObject> myMap = Maps.newLinkedHashMap();
public Map<SomeObject, SomeOtherObject> getMap() {
return Maps.newHashMap(myMap);
}
public void putMap(SomeObject a, SomeOtherObject b) {
myMap.put(a,b);
}
So, the above threw java.util.ConcurrentModificationException
and am trying to recreate the scenario. But no matter what I try, the system seems resilient. Here is what I tried:
1. Created 'n' threads some of which call getMap() and some call putMap()
2. Created 'n' threads that only call putMap() and one thread the is in an infinite loop that calls getMap()
3. Created 2 threads each of which alternates calling getMap() and putMap(). Meaning, thread-1 first calls get then put and thread-2 first calls put and then get.
None of the above works, either keeps running or goes to OOM. Any pointers on how to go about doing this?
EDIT
I believe the ConcurrentModificationException
is thrown when returning the copy of the map {Maps.newHashMap(myMap);
}. During this process the iterator creates a copy and while the iterator is at work, if the contents of the map are modified its not happy.
How do you fix Java's ConcurrentModificationException? There are two basic approaches: Do not make any changes to a collection while an Iterator loops through it. If you can't stop the underlying collection from being modified during iteration, create a clone of the target data structure and iterate through the clone.
The java. util. concurrentmodificationexception is an error in Java. The error occurs when the iterator is traversing a list, and a command is used to change an element's value during that traversal.
Assuming that you indeed use com.google.common.collect.Maps
, the implementation of newHashMap
is
public static <K, V> HashMap<K, V> newHashMap(Map<? extends K, ? extends V> map) {
return new HashMap<K, V>(map);
}
If we then look at the implementation of HashMap
:
public HashMap(Map<? extends K, ? extends V> m) {
this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
putAllForCreate(m);
}
and
private void [More ...] putAllForCreate(Map<? extends K, ? extends V> m) {
for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i
= m.entrySet().iterator(); i.hasNext(); ) {
Map.Entry<? extends K, ? extends V> e = i.next();
putForCreate(e.getKey(), e.getValue());
}
}
So indeed, the call to newHashMap
uses an iterator to traverse the map. As already pointed out by other answers, if putMap
is called while iterating the map, this will throw a ConcurrentModificationException
.
How can you reproduce this? I would say that two threads are enough: one repetitively calls getMap
, the other one putMap
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With