[英]Java Concurrent Modification Error HashMap
這里有趣的問題。 為什么第一個版本會拋出並發修改錯誤,而第二個版本則不會。 這會發生嗎?
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);
}
}
第一個示例引發異常,因為您在迭代時修改了地圖。 這是預料之中的。
在第二個示例中,您將創建一個包含地圖中所有字符串的ArrayList。 在這里迭代新創建的ArrayList,所以你的第二個例子不會拋出一個例子,因為你遍歷ArrayList,而不是遍歷地圖
這個
for(String key : map.keySet()){
if(map.get(key) < 50){
map.remove(key);
}
}
將始終拋出ConcurrentModificationException
因為您在迭代時刪除項目。 你需要的是一個具有remove
操作的Iterator
:
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();
}
}
還有ConcurrentHashMap
支持並發操作,只在需要時鎖定桶。
在第一種情況下,您會得到concurrentModificationException,因為在內部實現方面存在與迭代相關的修改計數。 如果修改計數在迭代期間發生更改,則會引發concurrentModificaitonException。
解決方案是使用iterator.remove()而不是直接從地圖中刪除元素。
在第二種情況下,在從地圖中刪除元素時,不是迭代地圖而是迭代不同的集合。 在這種情況下,修改計數在迭代期間永遠不會更改,因為您正在迭代不同的集合。
此外,在多線程環境中,在迭代之前始終對表示集合中的共享可變狀態的集合使用synchronized,否則可以獲得concurrentModificationException。
在多線程環境中,您的第二個解決方案將不正確,因為您尚未同步將原始映射的鍵集傳輸到新集合的語句。 因此有可能獲得concurrentModificationException。 在多線程環境中使用ConcurrentHashMap,同時知道默認情況下並非ConcurrentHashMap上的每個操作或操作集都是線程安全的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.