首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ConcurrentModificationException与ConcurrentHashMap

ConcurrentModificationException与ConcurrentHashMap
EN

Stack Overflow用户
提问于 2020-08-13 17:50:25
回答 2查看 2.2K关注 0票数 2

我理解它背后的概念,但我认为使用ConcurrentHashMap而不是HashMap会修复它。因为ConcurrentHashMap保护不受不同线程的并发读取和修改。

但我还是看到了例外。

这是代码片段-

SampleFile.java

代码语言:javascript
复制
prepareInfo(RequestHelper.getSender(request), someVar, concurrentMap);
....
...
    private void prepareInfo(final Sender sender, final SomeVar someVar, final ConcurrentHashMap<String,
            Object> concurrentMap){
        final Info info = RequestHelper.getInfo(someVar);
        someVar.setInfo(info);
        if(sender != null){
            prepareProfileInfo(sender.getUserDetails(), info, concurrentMap);
            mapDetailsWithMap(sender.getDetails(), concurrentMap);
            if(sender.getSenderId() != null){
                concurrentMap.put("sender_id", sender.getSenderId());
            }
            concurrentMap.putAll(sender.getAdditionalProperties());
        }
    }

错误堆栈跟踪是-

代码语言:javascript
复制
    at java.util.HashMap$HashIterator.nextNode(HashMap.java:1445)
    at java.util.HashMap$EntryIterator.next(HashMap.java:1479)
    at java.util.HashMap$EntryIterator.next(HashMap.java:1477)
    at java.util.concurrent.ConcurrentHashMap.putAll(ConcurrentHashMap.java:1083)
    at SampleFile.prepareAccountInfo(SampleFile.java:114)

有几个问题我不清楚-

  1. 为什么异常仍在发生?
  2. 有方法可以通过单元测试测试修复吗?
EN

回答 2

Stack Overflow用户

发布于 2020-08-13 17:54:57

这一行用sender.getAdditionalProperties()检索一个sender.getAdditionalProperties(),然后在HashMap上迭代,将每个项添加到concurrentMap中。

代码语言:javascript
复制
        concurrentMap.putAll(sender.getAdditionalProperties());

如果在迭代运行时修改了sender中的ConcurrentModificationException,那么您将得到一个ConcurrentModificationException。例外的意思是“在我迭代映射的时候修改了它的结构,所以我现在不知道该做什么”。

为了允许在sender对象中对映射进行并发修改和迭代,该映射应该是一个ConcurrentHashMap

要测试修复程序,可以进行以下测试:

代码语言:javascript
复制
Map<String,Object> map =  sender.getAdditionalProperties()
map.put("foo", "bar");
Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
// uh-oh - adding an item invalidates HashMap iterator
map.put("bar", "baz");
// Throws exception for HashMap
iterator.next();
票数 5
EN

Stack Overflow用户

发布于 2020-08-13 19:04:27

你犯了一个可以理解的非常常见的错误。

你看到了ConcurrentModificationException,你想:嗯。显然是线。

但那是不对的。名字是..。也许是不幸吧。

ConcurrentModificationException 与线程没有任何关系。

CoModEx仅仅意味着发生了这样一系列的事件:

  1. 您已经从集合中生成了迭代器,例如通过调用.iterator(),或者编写生成迭代器的for (var x : someCollection)。在创建迭代器之后的某个时间点,您可以以某种方式更改底层集合。您清除了它,添加了一些东西,更新了一个值,或者删除了一些东西。任何更改。使用步骤1中的迭代器执行任何操作,例如在步骤1上调用continue.

next(),或者您的for (var x : someCollection)到达结束大括号/运行一个.hasNext()

然后,砰。CoModEx。

这里有一种琐碎的方法。请注意,这个应用程序是完全单线程的:

代码语言:javascript
复制
class ThisAsplodes {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("Okay");
        for (String elem : list) {
            list.add("Bye");
        }
    }
}

编译,运行,然后,瞧。ConcurrentModificationException。对列表进行修改(添加“Bye”),然后在更改之前的迭代器(结束大括号)上进行迭代。

它变得更好了:如果您尝试使用普通的jane hashmap和多个线程来执行这个事件序列(一个线程制造迭代器,另一个线程修改它),那么CoModEx可能会发生,但是更多的事情通常只是以奇怪的方式中断。例如,您刚才添加的一个键似乎不在地图中。使用ConcurrentHashMap,您可以可靠地获得CoModEx。

从您的代码中可以看出,您要在哪里执行此操作,但至少现在您知道应该在哪里查看。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63400659

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档