在Java中使用并行流,但未获得预期值
我有一个关于单词计数的代码片段:在Java中使用并行流,但未获得预期值,java,Java,我有一个关于单词计数的代码片段: String[] wordCountArr = {"a", "b", "c", "a", "a", "b", "c", "d", "e"}; Stream.of(wordCountArr).collect(TreeMap::new, (treeMap, str) -> { Object countValue = treeMap.get(str); if
String[] wordCountArr = {"a", "b", "c", "a", "a", "b", "c", "d", "e"};
Stream.of(wordCountArr).collect(TreeMap::new,
(treeMap, str) -> {
Object countValue = treeMap.get(str);
if (countValue != null) {
Integer count = Integer.valueOf(countValue.toString());
treeMap.put(str, count + 1);
}
else {
treeMap.put(str, 1);
}
}, (treeMap, treeMap2) -> {
treeMap.putAll(treeMap2);
}).entrySet()
.forEach(System.out::println);
它得到了期望值:a=3b=2c=2d=1e=1,但collect函数的组合器似乎没有执行。然后我得到了这个:并将代码更改为:
Stream.of(wordCountArr).parallel().collect(TreeMap::new,
(treeMap, str) -> {
Object countValue = treeMap.get(str);
if (countValue != null) {
Integer count = Integer.valueOf(countValue.toString());
treeMap.put(str, count + 1);
}
else {
treeMap.put(str, 1);
}
}, (treeMap, treeMap2) -> {
treeMap.putAll(treeMap2);
}).entrySet()
.forEach(System.out::println);
但是结果不是预期的:a=1b=1c=1d=1e=1,我想可能putAll函数只是替换了旧的映射。有什么好主意可以得到正确的结果吗?使用并行流是否更有效?谢谢
已解决:
将putAll替换为merge当您使用并行流时,仅当框架尝试连接多个fork的结果时,才会执行合并器 因此,在第一个版本中,合并器不执行 第二个版本的代码可能会导致ConcurrentModificationException,因为使用并行流时树映射不是线程安全的 还有一点是,当您合并两棵树时,您忘记了对两棵树中的值求和。您将
treeMap
的所有内容与treeMap2
合并,因此treeMap
中的当前值被丢弃:treeMap.putAll(treeMap2)代码>
您必须手动迭代treeMap
中的键,将值与treeMap2
相加并返回
我不知道您为什么会提出这种方法,但要计算每组的商品数量,您只需使用groupingBy
:
Map<String, Long> countMap = Stream.of(wordCountArr).collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()));
Map countMap=Stream.of(wordCountArr).collect(collector.groupingBy(Function.identity()),
收集器。计数();
当您使用并行流时,只有当框架尝试连接多个fork的结果时,组合器才会执行
因此,在第一个版本中,合并器不执行
第二个版本的代码可能会导致ConcurrentModificationException,因为使用并行流时树映射不是线程安全的
还有一点是,当您合并两棵树时,您忘记了对两棵树中的值求和。您将treeMap
的所有内容与treeMap2
合并,因此treeMap
中的当前值被丢弃:treeMap.putAll(treeMap2)代码>
您必须手动迭代treeMap
中的键,将值与treeMap2
相加并返回
我不知道您为什么会提出这种方法,但要计算每组的商品数量,您只需使用groupingBy
:
Map<String, Long> countMap = Stream.of(wordCountArr).collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()));
Map countMap=Stream.of(wordCountArr).collect(collector.groupingBy(Function.identity()),
收集器。计数();
String[]wordCountArr={“a”、“b”、“c”、“a”、“a”、“b”、“c”、“d”、“e”};
Map countMap=Stream.of(wordCountArr).collect(Collectors.groupby(letter->letter,Collectors.counting());
countMap.forEach((s,count)->System.out.println(s+“:”+count));
String[]wordCountArr={“a”、“b”、“c”、“a”、“a”、“b”、“c”、“d”、“e”};
Map countMap=Stream.of(wordCountArr).collect(Collectors.groupby(letter->letter,Collectors.counting());
countMap.forEach((s,count)->System.out.println(s+“:”+count));
您应该有一个组合器逻辑,而不是使用putAll。必须迭代其中一个树映射,如果存在求和,然后插入,如果缺少键,则仅插入。您应该使用组合器逻辑,而不是使用putAll。必须迭代其中一个树状图,如果存在求和,然后插入,如果缺少键,则仅插入。谢谢您的回答。我知道分组的方法。如何确保类在java中是线程安全的?您需要阅读java中的线程和并发性,这个主题太大了,无法在这里讨论。但是在集合的情况下,您可以使用Collections.sychronizedXXX()确保集合是线程安全的。但是这个包装器没那么快。对于Map,有一个ConcurrentHashMap
,它具有线程安全和惊人的性能。我知道分组的方法。如何确保类在java中是线程安全的?您需要阅读java中的线程和并发性,这个主题太大了,无法在这里讨论。但是在集合的情况下,您可以使用Collections.sychronizedXXX()确保集合是线程安全的。但是这个包装器没那么快。对于Map,有一个ConcurrentHashMap
,具有线程安全和惊人的性能