简体   繁体   English

将 Future 的结果组合到 HashMap 时出现 java.util.ConcurrentModificationException

[英]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

From the docs :文档

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.

相关问题 从HashMap中删除元素时发生异常java.util.ConcurrentModificationException - Exception when removing element from HashMap java.util.ConcurrentModificationException 从哈希图中删除元素时出现 java.util.ConcurrentModificationException - java.util.ConcurrentModificationException when removing elements from a hashmap HashMap java.util.ConcurrentModificationException - HashMap java.util.ConcurrentModificationException java.util.ConcurrentModificationException:对哈希图的并发访问 - java.util.ConcurrentModificationException: concurrent access to hashmap 访问hashmap时出现java.util.ConcurrentModificationException - java.util.ConcurrentModificationException while accessing hashmap 从属性文件读取时java.util.ConcurrentModificationException - java.util.ConcurrentModificationException when read from Properties file 从列表中添加子列表/从列表中删除子列表时出现java.util.ConcurrentModificationException - java.util.ConcurrentModificationException when adding/removing SubLists from/to lists 重新加载表时出现java.util.ConcurrentModificationException - java.util.ConcurrentModificationException when reloading table 修改列表时出现java.util.ConcurrentModificationException - java.util.ConcurrentModificationException when modifying list 在预期时不抛出java.util.ConcurrentModificationException - java.util.ConcurrentModificationException not thrown when expected
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM