简体   繁体   English

如何在迭代Hashmap时获取ConcurrentModificationException?

[英]How I can get ConcurrentModificationException while iterating Hashmap?

I am trying to add a key value pair to the hashmap inside the Iterator method. 我试图将一个键值对添加到Iterator方法内的哈希图中。

But this is not giving me ConcurrentModificationException . 但这并没有给我ConcurrentModificationException Why? 为什么?

Since Hashmap is failfast. 由于Hashmap是fastfast。

Map<String,String> m = new HashMap<>();
           m.put("a", "a");

           Iterator<String> i = m.keySet().iterator();
           while(i.hasNext()){
               System.out.println(i.next());
               m.put("dsad", "asfsdf");

           }

If this is wrong, How i can produce ConcurrentModificationException ? 如果这是错误的,我如何产生ConcurrentModificationException? Thanks. 谢谢。

Update: Just checked. 更新:刚刚检查。

Map<String,String> m = new HashMap<>();
               m.put("a", "a");
          m.put("abc", "a");

               Iterator<String> i = m.keySet().iterator();
               while(i.hasNext()){
                   System.out.println(i.next());
                   m.put("dsad", "asfsdf");

               }

This is giving me the exception. 这给了我一个例外。

It happens that the concurrent modification check done by the HashMap code fails to detect this situation. 碰巧,由HashMap代码完成的并发修改检查无法检测到这种情况。 The code for HashMap 's iterator's hasNext in Oracle's JDK7 is: Oracle JDK7中HashMap的迭代器hasNext的代码是:

public final boolean hasNext() {
    return next != null;
}

...where (confusingly!) that next is a private data member in the iterator class (not to be confused with the next method on the Iterator interface — to my mind, calling that data member next was a very poor choice). ...在哪里(令人困惑!) next是迭代器类中的私有数据成员(不要与Iterator接口上的next方法相混淆-在我看来,将数据成员称为next是一个非常糟糕的选择)。

Note that it doesn't do the check for concurrent modifications. 请注意,它不会检查并发修改。 Contrast with this code that is called (indirectly) from Iterator#next : 与此代码(从Iterator#next间接调用)对比:

    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();

...which does do the check. ......这确实做检查。

So here's what happens in your code: 因此,这就是您的代码中发生的情况:

  1. You create a HashMap . 您创建一个HashMap
  2. You add one entry to it. 您添加一个条目。
  3. You begin an iteration. 您开始迭代。
  4. hasNext is true, so you go into the body of your loop. hasNext是真的,因此您进入了循环的主体。
  5. You get the element from next ; next元素; at this point, the iterator remembers what the next element should be on its internal data member (the confusingly-named next ), and in this case since there's no next element in the map, that next data member is set to null , meaning that the iteration is complete. 在这一点上,迭代器会记住下一个元素应该在其内部数据成员上的名称(这个名称易混淆的next ),在这种情况下,由于映射中没有下一个元素,因此next数据成员被设置为null ,这意味着迭代完成。
  6. You add to the map. 您添加到地图。
  7. Your code calls hasNext , which sees the next data member is null and returns false . 您的代码调用hasNext ,它看到next数据成员为null并返回false

If you had two elements in the map before starting your loop instead of one, you'd get the exception (from next ). 如果在开始循环之前在映射中有两个元素而不是一个,则将获得异常(来自next )。

I've previously argued this is, or is very nearly, a bug, but it's a pretty fuzzy area, and others have argued quite reasonably that it isn't. 我以前曾说过,这是一个bug,或者几乎是一个bug,但这是一个非常模糊的领域,而其他人则相当合理地认为不是。 The documentation doesn't say specifically which methods of Iterator<E> will throw the exception, just that it will get thrown. 该文档没有具体说明Iterator<E>哪些方法将引发异常,而只是引发该异常。 The documentation also says it's only thrown on a "best effort" basis, it's not guaranteed. 该文档还说,这只是出于“尽力而为”的原则,不能保证。

Whether one considers this a bug or not, it's unlikely to be changed at this point, as the pain of changing it (breaking some existing code that probably shouldn't have relied on this behavior) far outweighs the benefit (possibly being more "correct"). 无论是否认为它是一个错误,在这一点上都不太可能更改,因为更改它的痛苦(破坏一些本不应该依赖此行为的现有代码)远远超过了好处(可能更“正确”) “)。

The iterator may throw ConcurrentModificationException but is not guaranteed to. 迭代器可能会抛出ConcurrentModificationException,但不能保证如此。

From the javadoc of HashMap: 从HashMap的javadoc中:

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. 请注意,迭代器的快速失败行为无法得到保证,因为通常来说,在存在不同步的并发修改的情况下,不可能做出任何严格的保证。 Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. 快速失败的迭代器会尽最大努力抛出ConcurrentModificationException。 Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs. 因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应仅用于检测错误。

Try this: 尝试这个:

  Map<String,String> m = new HashMap<>();
    m.put("a", "a");

    Iterator<String> i = m.keySet().iterator();
    while(i.hasNext()){
        m.remove("a");
        System.out.println(i.next());


    }

暂无
暂无

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

相关问题 通过HashMap迭代时出现ConcurrentModificationException - ConcurrentModificationException while iterating through HashMap 为什么我在同时迭代和修改HashMap时没有得到“ConcurrentModificationException”? - How come I am not getting “ConcurrentModificationException” while iterating and modifying on HashMap at the same time? 如何在避免ConcurrentModificationException的同时迭代HashMap - How to iterate over a HashMap while avoiding ConcurrentModificationException 迭代此集合时如何避免ConcurrentModificationException? - How to avoid ConcurrentModificationException while iterating this collection? 如何在迭代时添加到 HashMap 内的 ArrayList - How Do I add to an ArrayList within a HashMap while iterating 如何在并发线程中操作`values()`和`put()`时避免使用HashMap“ConcurrentModificationException”? - How to avoid HashMap “ConcurrentModificationException” while manipulating `values()` and `put()` in concurrent threads? 可以在没有迭代的情况下在 HashMap 中获取、放置和删除元素导致 ConcurrentModificationException? - Can get, put & remove element in HashMap without iteration cause ConcurrentModificationException? HashMap ConcurrentModificationException同时初始化另一个HashMap - HashMap ConcurrentModificationException while initializing with another HashMap 如何在迭代 map.entrySet 时避免 ConcurrentModificationException - How to avoid ConcurrentModificationException while iterating over map.entrySet 我如何应对ConcurrentModificationException? - How can i counter a ConcurrentModificationException?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM