[英]java.util.ConcurrentModificationException when combing results from Future's into HashMap
I'm running into an issue where I intermittently get an java.util.ConcurrentModificationException error whilst merging the results of futures.我遇到了一个问题,我在合并期货结果时间歇性地收到java.util.ConcurrentModificationException错误。 I've tried making all my HashMaps concurrent and I tried using an iterator but the error still persists and I'm totally confused to how this error is occurring.
我已经尝试使我所有的 HashMaps 并发并且我尝试使用迭代器但错误仍然存在,我完全不知道这个错误是如何发生的。 I'm not looping through the same HashMap I'm inserting too either (as done in similar questions with this error).
我也没有遍历我插入的同一个 HashMap (就像在类似问题中所做的那样)。
For my code, to start off with I build a bunch of tasks that return's HashMap<String, HashSet>, then using .invokeAll my tasks all return the above HashMap which I then try to merge together (I'm reading a large CSV to get all unique results for each column).对于我的代码,首先我构建了一堆返回 HashMap<String, HashSet> 的任务,然后使用 .invokeAll 我的任务都返回上面的 HashMap,然后我尝试将其合并在一起(我正在读取一个大的 CSV 到获取每列的所有唯一结果)。
I start by defining all the keys.我首先定义所有键。
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<>());
}
I then make my tasks, which clone the keys, do the processing and return it's result然后我做我的任务,克隆密钥,进行处理并返回结果
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;
});
I invokeAll the tasks, where the results are put into a List of Future's我调用所有的任务,其中的结果被放入一个未来的列表中
ExecutorService es = Executors.newCachedThreadPool();
List<Future<HashMap<String, HashSet<String>>>> futures = null;
try {
futures = es.invokeAll(tasks);
es.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
}
I then, for very safe keeping, make a ConruentHashMap with a copy of all the keys pre-defined.然后,为了非常安全,我使用预定义的所有键的副本制作了一个 ConruentHashMap。 I then loop through all the results from my tasks, put them into a ConcurrentHashMap as well, and addAll the results into the original copied ConcurrentHashMap with the pre-defined keys.
然后我循环遍历我的任务的所有结果,将它们也放入 ConcurrentHashMap 中,并使用预定义的键将所有结果添加到原始复制的 ConcurrentHashMap 中。 This is when the error occurs (only sometimes though, which backs that it's something to do with threads, but I thought all the threading stuff is done at this point?).
这是发生错误的时间(尽管只是有时,这表明它与线程有关,但我认为此时所有线程处理工作都已完成?)。
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();
}
Here is the error in full:这是完整的错误:
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)
I'm really not sure why this is causing an error, as addAll is only run on the main thread, and it's inserting into a ConCurrent HashMap too anyway - any ideas on why this is happening would be hugely appreciated!我真的不知道为什么这会导致错误,因为 addAll 只在主线程上运行,而且它也插入到 ConCurrent HashMap 中 - 关于为什么会发生这种情况的任何想法将不胜感激!
The problem is that headersHashset.clone()
doesn't clone HashSet
s in the values.问题是
headersHashset.clone()
不会在值中克隆HashSet
。
Returns a shallow copy of this HashMap instance: the keys and values themselves are not cloned.
返回此 HashMap 实例的浅表副本:不会克隆键和值本身。
It means that localHeadersHashset
in your tasks, and your headersHashsetConcurrent
, and threadSafeItems
returned by futures
— all of these use the same HashSet
objects for the same keys.这意味着
localHeadersHashset
在你的任务,你的headersHashsetConcurrent
,并threadSafeItems
由归国futures
-所有这些使用相同HashSet
为同一键的对象。
Since tasks are executed in parallel threads, it is entirely possible that some task executes HashSet.add()
at the same time when the main thread iterates over the elements of the same HashSet
inside:由于任务是在并行线程中执行的,完全有可能在主线程对内部同一个
HashSet
的元素进行迭代时,某个任务同时执行了HashSet.add()
:
headersHashsetConcurrent.get(items.getKey()).addAll(items.getValue());
This is what causes your ConcurrentModificationException
.这就是导致您的
ConcurrentModificationException
原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.