Collectors.toConcurrentMap 和通过 Collectors.toMap 供应商选项将 Map 转换为 ConcurrentHashMap 之间有什么区别?

What is the difference between Collectors.toConcurrentMap and converting a Map to ConcurrentHashMap via Collectors.toMap supplier option?

我想通过 Java 8 StreamCollector 接口将 Map 转换为 ConcurrentHashMap,我可以使用两个选项.

第一个:

Map<Integer, String> mb = persons.stream()
                                 .collect(Collectors.toMap(
                                            p -> p.age, 
                                            p -> p.name, 
                                            (name1, name2) -> name1+";"+name2,
                                            ConcurrentHashMap::new));

第二个:

Map<Integer, String> mb1 = persons.stream()
                                  .collect(Collectors.toConcurrentMap(
                                             p -> p.age, 
                                             p -> p.name));

哪个更好?我应该什么时候使用每个选项?

来自 toMap 的 Javadoc :

The returned Collector is not concurrent. For parallel stream pipelines, the combiner function operates by merging the keys from one map into another, which can be an expensive operation. If it is not required that results are inserted into the Map in encounter order, using toConcurrentMap(Function, Function) may offer better parallel performance.

toConcurrentMap 不会按遇到顺序将结果插入 Map,但应该会提供更好的性能。

如果不在意插入顺序,建议使用toConcurrentMap并行流

它们在处理并行流时是有区别的。

toMap -> 是非并发收集器

toConcurrentMap -> 是并发收集器(这个从它们的特点就可以看出)。

区别在于toMap会创建多个中间结果,然后合并在一起(这样的Collector的Supplier会被多次调用),而toConcurrentMap 将创建一个 单个 结果,每个线程都会向它抛出结果(这种收集器的供应商只会被调用一次)

为什么这很重要?这涉及插入顺序(如果重要的话)。

toMap 将通过合并多个中间结果(该收集器的供应商被多次调用以及组合器)

toConcurrentMap 将通过将所有元素放入公共结果容器(在本例中为 ConcurrentHashMap)以任何顺序(未定义)收集元素。 Supplier 只被调用一次,Accumulator 被调用多次而 Combiner 永远不会被调用。

这里的小警告是 CONCURRENT 收集器不调用合并:流必须具有 UNORDERED 标志 - 通过 unordered() 显式调用或当流的源未排序时(例如 Set)。