簡體   English   中英

Java:使用 HashMap 迭代器優於 ConcurrentHashMap 有什么優勢?

[英]Java: What is the advantage of using HashMap iterator over ConcurrentHashMap?

我有一個使用 Map 的單線程程序,其中在迭代時將一項一項刪除。 我已經讀過可以在這里使用迭代器來避免ConcurrentModificationException但為什么不使用 ConcurrentHashMap 來代替它似乎更干凈?

我的代碼:

private final Map<Integer, Row> rowMap;


.....

private void shutDown() {

  for (Integer rowNumber : rowMap.keySet()) {
    closeRow(rowNumber)
    deleteRow(rowNumber)
  }
}

....

在 closeRow() 方法中:

private void closeRow(Integer rowNumber) {
    Row row = rowMap.remove(rowNumber);
    if (row != null) {
      row();
    }
}

deleteRow() 方法也類似。

對於我的場景,使用迭代器意味着將其聲明為 final,以便 closeRow() 和 deleteRow() 方法可以訪問它以將其刪除。 此外, iterator.remove() 方法不會返回要刪除的項目的值,這在我的情況下是必需的。

我的問題是,最有效的方法是什么,它不會拋出 ConcurrentModificationException? 是使用迭代器還是將 rowMap 設為 ConcurrentHashMap?

僅當它在線程之間共享時才使用ConcurrentHashMap

在單線程中,如果在使用迭代器時修改 object,則會引發CurrentModificationException

有兩種方法可以從集合中刪除元素,例如列表和 map。 一種是在集合上調用 remove。 另一種是使用迭代器。 但它們不能一起使用。 如果使用集合 object 的 remove 方法刪除元素,它將使迭代器的 state 無效。

List<Integer> list = new ArrayList(List.of(1,2,3,4,5));
Iterator<Integer> it = list.iterator();
list.remove(0);
        
while(it.hasNext()){
  System.out.print(it.next());
}

這是一個例外:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
    at Main.main(Main.java:15)

這是一個相當簡單的迭代器模式。

Iterator<Map.Entry<Integer,Row>> it = rowMap.entrySet();
while (it.hasNext()) {
   Map.Entry<Integer,Row> ent = it.next();
   it.remove();
   // ... do what you want with ent.getKey() and ent.getValue();
}

你可以。 事實上, MapConcurentMap並沒有像List接口那樣提供迭代器。 但是您可以使用map.entrySet().iterator();

如果你這樣做,你會得到一個 concurrentModifcation 異常。

Map<Integer,Integer> map = new HashMap<>(Map.of(1,2,2,2,3,2,4,2,5,3,6,3,7,3));

for(int key : map.keySet()) {
    map.put(key*10,4);
}

但在這里你不會

Map<Integer,Integer> map = new ConcurrentHashMap<>(Map.of(1,2,2,2,3,2,4,2,5,3,6,3,7,3));

for(int key : map2.keySet()) {
    map2.put(key*10,4);
} 

您可以以相同的方式刪除密鑰。 請注意, keySet()返回鍵的視圖,因此您可以看到剛剛添加的一些(但可能不是全部)鍵。 我相信這個過程是非決定性的,因為它取決於鍵的 hash。

這是迭代器的方式。

Iterator<Entry<Integer,Integer>> iter= map.entrySet().iterator();

while(iter.hasNext()) {
    iter.next();
    iter.remove();
}
System.out.println(map); // prints {}

ConcurrentHashMaps主要用於多線程環境,但您可以使用它們來避免並發修改異常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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