[英]Exception when removing element from HashMap java.util.ConcurrentModificationException
[英]java.util.ConcurrentModificationException when combing results from Future's into HashMap
我遇到了一个问题,我在合并期货结果时间歇性地收到java.util.ConcurrentModificationException错误。 我已经尝试使我所有的 HashMaps 并发并且我尝试使用迭代器但错误仍然存在,我完全不知道这个错误是如何发生的。 我也没有遍历我插入的同一个 HashMap (就像在类似问题中所做的那样)。
对于我的代码,首先我构建了一堆返回 HashMap<String, HashSet> 的任务,然后使用 .invokeAll 我的任务都返回上面的 HashMap,然后我尝试将其合并在一起(我正在读取一个大的 CSV 到获取每列的所有唯一结果)。
我首先定义所有键。
HashMap<String, HashSet<String>> headersHashset = new HashMap<String, HashSet<String>>();
headers = Arrays.asList(br.readLine().split(delimiter));
for (String headerID : headers) {
headersHashset.put(headerID, new HashSet<>());
}
然后我做我的任务,克隆密钥,进行处理并返回结果
tasks.add(() -> {
HashMap<String, HashSet<String>> localHeadersHashset = (HashMap<String, HashSet<String>>) headersHashset.clone();
for (String[] values : sampleSet.values()) { // sampleSet is a SortedMap<Integer, String[]>
int headerAsINT = 0;
for (String value : values) {
localHeadersHashset.get(headers.get(headerAsINT)).add(value);
headerAsINT++;
}
}
return localHeadersHashset;
});
我调用所有的任务,其中的结果被放入一个未来的列表中
ExecutorService es = Executors.newCachedThreadPool();
List<Future<HashMap<String, HashSet<String>>>> futures = null;
try {
futures = es.invokeAll(tasks);
es.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
}
然后,为了非常安全,我使用预定义的所有键的副本制作了一个 ConruentHashMap。 然后我循环遍历我的任务的所有结果,将它们也放入 ConcurrentHashMap 中,并使用预定义的键将所有结果添加到原始复制的 ConcurrentHashMap 中。 这是发生错误的时间(尽管只是有时,这表明它与线程有关,但我认为此时所有线程处理工作都已完成?)。
ConcurrentHashMap<String, HashSet<String>> headersHashsetConcurrent = new ConcurrentHashMap<>(headersHashset);
try {
for (Future<HashMap<String, HashSet<String>>> f : futures) {
ConcurrentHashMap<String, HashSet<String>> threadSafeItems = new ConcurrentHashMap<>(f.get());
for (Map.Entry<String, HashSet<String>> items : threadSafeItems.entrySet()) {
headersHashsetConcurrent.get(items.getKey()).addAll(items.getValue()); // ERROR SHOWS HERE
}
}
} catch (Exception e) {
e.printStackTrace();
}
这是完整的错误:
java.util.ConcurrentModificationException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1584)
at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1607)
at java.base/java.util.AbstractCollection.addAll(AbstractCollection.java:335)
at project/project.parseCSV.processFile(parseCSV.java:101)
at project/project.parseCSV.call(parseCSV.java:126)
at project/project.parseCSV.call(parseCSV.java:11)
at javafx.graphics/javafx.concurrent.Task$TaskCallable.call(Task.java:1425)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.lang.Thread.run(Thread.java:832)
我真的不知道为什么这会导致错误,因为 addAll 只在主线程上运行,而且它也插入到 ConCurrent HashMap 中 - 关于为什么会发生这种情况的任何想法将不胜感激!
问题是headersHashset.clone()
不会在值中克隆HashSet
。
从文档:
返回此 HashMap 实例的浅表副本:不会克隆键和值本身。
这意味着localHeadersHashset
在你的任务,你的headersHashsetConcurrent
,并threadSafeItems
由归国futures
-所有这些使用相同HashSet
为同一键的对象。
由于任务是在并行线程中执行的,完全有可能在主线程对内部同一个HashSet
的元素进行迭代时,某个任务同时执行了HashSet.add()
:
headersHashsetConcurrent.get(items.getKey()).addAll(items.getValue());
这就是导致您的ConcurrentModificationException
原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.