我理解它背后的概念,但我认为使用ConcurrentHashMap而不是HashMap会修复它。因为ConcurrentHashMap保护不受不同线程的并发读取和修改。
但我还是看到了例外。
这是代码片段-
SampleFile.java
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());
}
}错误堆栈跟踪是-
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)有几个问题我不清楚-
发布于 2020-08-13 17:54:57
这一行用sender.getAdditionalProperties()检索一个sender.getAdditionalProperties(),然后在HashMap上迭代,将每个项添加到concurrentMap中。
concurrentMap.putAll(sender.getAdditionalProperties());如果在迭代运行时修改了sender中的ConcurrentModificationException,那么您将得到一个ConcurrentModificationException。例外的意思是“在我迭代映射的时候修改了它的结构,所以我现在不知道该做什么”。
为了允许在sender对象中对映射进行并发修改和迭代,该映射应该是一个ConcurrentHashMap。
要测试修复程序,可以进行以下测试:
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();发布于 2020-08-13 19:04:27
你犯了一个可以理解的非常常见的错误。
你看到了ConcurrentModificationException,你想:嗯。显然是线。
但那是不对的。名字是..。也许是不幸吧。
ConcurrentModificationException 与线程没有任何关系。
CoModEx仅仅意味着发生了这样一系列的事件:
.iterator(),或者编写生成迭代器的for (var x : someCollection)。在创建迭代器之后的某个时间点,您可以以某种方式更改底层集合。您清除了它,添加了一些东西,更新了一个值,或者删除了一些东西。任何更改。使用步骤1中的迭代器执行任何操作,例如在步骤1上调用continue.或next(),或者您的for (var x : someCollection)到达结束大括号/运行一个.hasNext()。
然后,砰。CoModEx。
这里有一种琐碎的方法。请注意,这个应用程序是完全单线程的:
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。
从您的代码中可以看出,您要在哪里执行此操作,但至少现在您知道应该在哪里查看。
https://stackoverflow.com/questions/63400659
复制相似问题