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()) {
    deleteRow(rowNumber)
  }
}

....

对于我的场景,使用迭代器意味着将其声明为最终的,因此 closeRow() 和 deleteRow() 方法可以访问它以将其删除。此外,iterator.remove() 方法不会 return 正在删除的项目的值,这在我的情况下是必需的。

我的问题是,为了不抛出 ConcurrentModificationException,最有效的方法是什么?是使用迭代器还是让 rowMap 成为 ConcurrentHashMap?

这是一个相当简单的迭代器模式。

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

因此,我们使用显式迭代器遍历映射,这允许我们在迭代期间使用迭代器的 remove 方法。我们正在迭代映射的“条目集”视图,这使我们能够从单个迭代器中检索键和值。

Documentation link

public Set<Map.Entry<K,V>> entrySet()

Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined.

只有在线程间共享时才使用 ConcurrentHashMap

在单线程中,当使用迭代器修改对象时抛出CurrentModificationException

有两种方法可以从列表和地图等集合中删除元素。一种是在集合上调用 remove。另一个是使用迭代器。但它们不能一起使用。如果您使用集合对象的 remove 方法删除一个元素,它会使迭代器的状态无效。

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)