java何时使用收集器。按并发分组?
我无法理解Collectors.groupingByConcurrent
的确切用例。
从JavaDocs:
Returns a concurrent Collector implementing a cascaded "group by" operation on input elements of type T...
This is a concurrent and unordered Collector.
...
也许这里的关键词是级联的“分组方式”。这是否表明了催收员是如何进行实际积累的?(从源头上看,它很快变得错综复杂)
当我用一个假ConcurrentMap
测试它时
class FakeConcurrentMap<K, V> extends HashMap<K, V>
implements ConcurrentMap<K, V> {}
我发现它会用并行流中断(因为映射不是线程安全的,所以会给出错误的聚合):
Map<Integer, Long> counts4 = IntStream.range(0, 1000000)
.boxed()
.parallel()
.collect(
Collectors.groupingByConcurrent(i -> i % 10,
FakeConcurrentMap::new,
Collectors.counting()));
如果没有.parallel()
,结果总是正确的。所以groupingByConcurrent
似乎与并行流相关联
但是,就我所见,以下用groupingBy
收集的并行流总是产生正确的结果:
Map<Integer, Long> counts3 = IntStream.range(0, 1000000)
.boxed()
.parallel()
.collect(
Collectors.groupingBy(i -> i % 10,
HashMap::new,
Collectors.counting()));
那么,什么时候使用groupingByConcurrent
而不是groupingBy
是正确的(当然,这不能仅仅是将分组作为并发映射获得)
# 1 楼答案
对于并行流,所有收集器都可以正常工作,但支持直接并发(使用
Collector.Characteristics.CONCURRENT
)的收集器有资格进行其他收集器不具备的优化groupingByConcurrent
属于这一类(大致来说,发生的情况是,非并发收集器将输入分解为每个线程的部分,每个线程创建一个累加器,然后在最后将它们合并。并发(无序)收集器创建一个累加器,并让多个工作线程将元素并发合并到同一个累加器中。)