首页 > 解决方案 > Java如何并行迭代HashMap的所有值

问题描述

我有一个HashMapwith Key 的 typeHashSet和 Value 的 type ArrayList

将所有键值对插入到Map. 我想迭代每个键及其值以进行进一步处理,而不仅仅是打印,它将在键和值作为字符串参数传递的进一步过程中使用。

所以我在想这是否可能,而不是在 Map 中一次迭代每个键值对,即等待第一次迭代完成整个过程,然后才开始下一次迭代。相反,如果可以并行迭代所有键值而不必等待轮到它,那么整体结果会更快。迭代的顺序并不重要。它应该只并行读取所有键值对。

我尝试了 Stream API,但这只是并行打印所有迭代值,但在进一步的过程中,它没有做我期望的事情,也许我做错了什么,因为我不熟悉 Streams。如果这不能通过可用的内置函数或类来实现,那么即使是第三方 Jars(Apache-commons)也可以。

这是我到目前为止尝试过的代码:

String jobId = "J1";
Map<Set<String>,List<String>> map_batch_result_details = new HashMap<Set<String>,List<String>>();
Set<String> hs_batchesId= new HashSet<String>();
List<String> list_resultId = new ArrayList<String>();

hs_batchesId.add("B1"); 
hs_batchesId.add("B2"); 
hs_batchesId.add("B3");

list_resultId.add("R1");
list_resultId.add("R2");
list_resultId.add("R3");


map_batch_result_details.put(hs_batchesId, list_resultId); 

map_batch_result_details.entrySet().stream().forEach(e -> {
System.out.format("key: %s, value: %s%n", e.getKey(), e.getValue());  // for printing results using stream without iterating each row sequentially instead iterates it parallely

 InputStream inputStream =  Connection.getQueryResultStream(jobId, e.getKey().toString(), e.getValue().toString());
/*
getQueryResultStream expects one batchId which is  <Key> of Map but it needs it in String so I am using toString
similarly third parameter expects one resultId which is <value> of Map again in String so toString
But Code fails as it is not passing 1 key and 1 value, rather it passes all key values at once in single call.
*/

});

输出

CALL: getQueryResultStream(jobId, e.getKey().toString(),e.getValue().toString());

**Actual values passed**
 getQueryResultStream(J1,[B1,B2,B3],[R1,R2,R3])

**Expected values**
getQueryResultStream(J1,B1,R1)
getQueryResultStream(J1,B2,R2)
getQueryResultStream(J1,B3,R3)

Expected value should execute in Parallel without having to wait for first iteration to get over. But not in one call which is happening in Actual values.

标签: javajava-8parallel-processinghashmapjava-stream

解决方案


我有一个HashMapwith Key 的 typeHashSet和 Value 的 type ArrayList

这就是问题。无论键/值内部是什么,唯一的一个条目。此外,只要是无序的,这种结构就不能保证"B1"和绑定在一起。"R1"HashSet

我推荐使用不同结构的方式。您使用 a Map,其中只有一个条目同时具有键和值作为集合,这对于同时迭代是不切实际的。

我建议使用自定义或任何导入类的列表Pair<T, R>(使用 getter 方法say firstand second)或者Entry<K, V>以相同的方式工作:

List<Entry<String, String>> entries = new ArrayList<>();
entries.add(new SimpleEntry<>("B1", "R1"));
entries.add(new SimpleEntry<>("B2", "R2"));
entries.add(new SimpleEntry<>("B3", "R3"));

entries.parallelStream()
       .forEach(e -> System.out.format("key: %s, value: %s%n", e.getKey(), e.getValue()));

只要 Stream 是并行的,forEach输出就是无序的并且看起来是随机的。示例输出:

key: B2, value: R2
key: B1, value: R1
key: B3, value: R3

顺便说一句,您可能想要继续流式传输而不是使用forEach

entries.parallelStream()
       .map(e-> Connection.getQueryResultStream(jobId, e.getKey(), e.getValue()))
       ...

编辑:如果输入是Map<Set<String>, List<String>>并且您无法更改它,则将其转换为List<Entry<String, String>>使用以下代码段。唯一的希望是Set维持LinkedHashSet秩序,键和值之间的联系将保持原意:

map_batch_result_details.forEach((k, v) -> {
    Iterator<String> keysIterator = k.iterator();
    Iterator<String> valuesIterator = v.iterator();
    while (keysIterator.hasNext() && valuesIterator.hasNext()) {
        String key = keysIterator.next();
        String value = valuesIterator.next();
        entries.add(new SimpleEntry<>(key, value));
        }
    }
);

推荐阅读