简体   繁体   English

Java:使用 HashMap 迭代器优于 ConcurrentHashMap 有什么优势?

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

I have a program that is single-threaded that uses a Map where items are removed one by one while iterating.我有一个使用 Map 的单线程程序,其中在迭代时将一项一项删除。 I have read that iterator can be used here to avoid ConcurrentModificationException but why not use ConcurrentHashMap instead which seems to be much cleaner?我已经读过可以在这里使用迭代器来避免ConcurrentModificationException但为什么不使用 ConcurrentHashMap 来代替它似乎更干净?

My code:我的代码:

private final Map<Integer, Row> rowMap;


.....

private void shutDown() {

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

....

And in closeRow() method:在 closeRow() 方法中:

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

And similar for the deleteRow() method too. deleteRow() 方法也类似。

For my scenario, using a iterator means declaring it final so closeRow() and deleteRow() methods have access to it for removing it.对于我的场景,使用迭代器意味着将其声明为 final,以便 closeRow() 和 deleteRow() 方法可以访问它以将其删除。 Additionally, the iterator.remove() method does not return the value of the item being removed which is necessary in my case.此外, iterator.remove() 方法不会返回要删除的项目的值,这在我的情况下是必需的。

My question is, what is the most efficient way to do it so it doesn't throw ConcurrentModificationException?我的问题是,最有效的方法是什么,它不会抛出 ConcurrentModificationException? Is it using an iterator or making rowMap a ConcurrentHashMap?是使用迭代器还是将 rowMap 设为 ConcurrentHashMap?

Use ConcurrentHashMap only if it's shared among threads.仅当它在线程之间共享时才使用ConcurrentHashMap

In single thread, CurrentModificationException is thrown when the object is modified while an iterator is being used.在单线程中,如果在使用迭代器时修改 object,则会引发CurrentModificationException

There are two ways to remove elements from a collection such as list and map.有两种方法可以从集合中删除元素,例如列表和 map。 One is by calling remove on the collection.一种是在集合上调用 remove。 The other is using an iterator.另一种是使用迭代器。 But they can't be used together.但它们不能一起使用。 If you remove an element using the remove method of the collection object, it would invalidate the state of the iterator.如果使用集合 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());
}

Here's the exception:这是一个例外:

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)

It's a fairly straightforward iterator pattern.这是一个相当简单的迭代器模式。

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();
}

You can.你可以。 In fact, the Map or ConcurentMap don't provide an iterator like the List interface.事实上, MapConcurentMap并没有像List接口那样提供迭代器。 But you can use the iterator from map.entrySet().iterator();但是您可以使用map.entrySet().iterator();

If you do this you will get a concurrentModifcation exception.如果你这样做,你会得到一个 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);
}

But here you won't但在这里你不会

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);
} 

You can remove the keys in the same way.您可以以相同的方式删除密钥。 Note that keySet() returns a view of the keys so you see some (but perhaps not all) of the keys you just added.请注意, keySet()返回键的视图,因此您可以看到刚刚添加的一些(但可能不是全部)键。 I believe this process is non-determinant since it depends on the hash of the keys.我相信这个过程是非决定性的,因为它取决于键的 hash。

And here is the iterator way.这是迭代器的方式。

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

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

ConcurrentHashMaps are primarily for use in multiple thread environments but you can use them to avoid concurrent modification exceptions to. ConcurrentHashMaps主要用于多线程环境,但您可以使用它们来避免并发修改异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM