簡體   English   中英

Java並發修改錯誤HashMap

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM