Java HashMap concurrent modification error

Interesting question here. Why does the first version of this throw throws a concurrent modification error while the second doesn't. If this happens?

Map<String,Integer> map = new HashMap<>();    
... // Populate the map
for(String key : map.keySet()){
    if(map.get(key) < 50){
        map.remove(key);
    }
}

Map<String,Integer> map = new HashMap<>();    
... // Populate the map
for(String key : new ArrayList<String>(map.keySet())){
    if(map.get(key) < 50){
        map.remove(key);
    }
}

      

+3


source to share


3 answers


The first example throws an exception because you are modifying the map while iterating over it. This is expected.



In the second example, you create an ArrayList containing all the lines in the map. Here you are iterating over the newly created ArrayList, so your second example does not throw the example because you are iterating over the ArrayList, not over the map

+4


source


it

for(String key : map.keySet()){
    if(map.get(key) < 50){
        map.remove(key);
    }
}

      

will always throw ConcurrentModificationException

because you are removing elements during iteration. You will need Iterator

one that has an operation remove

:



for(Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator(); it.hasNext(); ) {
    Map.Entry<String, Integer> entry = it.next();
    if(entry.getValue() < 50) {
      it.remove();
    }
}

      

There is also ConcurrentHashMap

one that supports concurrent operations and only blocks buckets if you need to.

0


source


In the first case, you get a concurrentModificationException, because the number of changes associated with the iteration is in terms of internal implementation. If the number of changes changes during iteration, a concurrentModificaitonException is thrown.

The solution is to use iterator.remove () instead of removing the element directly from the map.

In the second case, you are repeating not a map, but a different collection, removing the element from the map. In this case, the revision counter never changes during iteration because you are iterating over a different collection.

Also, in a multi-threaded environment, always use sync on the collection that represents the shared mutable state in the class before iterating it, otherwise you might get a concurrentModificationException.

In a multi-threaded environment, your second solution will not be correct because you have not synchronized the statement in which you are passing the source map set to the new collection. Thus, it is possible to get a concurrentModificationException. Use ConcurrentHashMap in a multithreaded environment, knowing that not every operation or set of operations in ConcurrentHashMap is insecure by default.

0


source







All Articles