【问题标题】:What is the difference between Collectors.toConcurrentMap and converting a Map to ConcurrentHashMap via Collectors.toMap supplier option?Collectors.toConcurrentMap 和通过 Collectors.toMap 供应商选项将 Map 转换为 ConcurrentHashMap 有什么区别?
【发布时间】:2017-04-14 18:29:04
【问题描述】:

我想通过 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));

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

【问题讨论】:

    标签: java java-8 java-stream concurrenthashmap collectors


    【解决方案1】:

    来自toMap的Javadoc:

    返回的收集器不是并发的。对于并行流管道,组合器功能通过将键从一个映射合并到另一个映射来操作,这可能是一项昂贵的操作。如果不需要将结果按遇到顺序插入 Map,使用 toConcurrentMap(Function, Function) 可能会提供更好的并行性能。

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

    如果你不关心插入顺序,如果你使用并行流,建议使用toConcurrentMap

    【讨论】:

      【解决方案2】:

      在处理并行流时,它们之间存在差异。

      toMap -> 是一个非并发收集器

      toConcurrentMap -> 是并发收集器(这可以从它们的特性上看出来)。

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

      为什么这很重要?这涉及广告订单(如果重要的话)。

      toMap 将通过合并多个中间结果(多次调用该收集器的供应商以及组合器)以遇到顺序将值插入结果地图中

      toConcurrentMap 将通过将所有元素扔到一个公共结果容器(在本例中为 ConcurrentHashMap)以任何顺序(未定义)收集元素。供应商只被调用一次,累加器被多次调用,而组合器从不被调用。

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

      【讨论】:

      • 如果流不是并行的,它会有所不同吗?我看到的唯一区别是它只是将特征标志添加到 CollectorImpl 然后它根据该标志(插入顺序)进行评估,但如果不是并行流这两种方法的行为相同,除了一个产生 HashMap 另一个产生 ConcurrentHashMap,我的意思是它只影响当前流的行为,如果它是并行的。
      • @Bolzano 在非并行流中,不会为任一实现调用组合器。合并将在累加器中完成(调用尽可能多的元素,而供应商只会被调用一次)。所以是的,唯一明显的区别是您将得到的结果:HashMap 与 ConcurrentHashMap。在底层,toMap 调用 HashMap::merge,而 toConcurrentMap 调用 ConcurrentHashMap::merge。所以如果你在做串行处理,你为什么会想要 ConcurrentHashMap?
      • 我们需要向@KaranVerma 询问,在他的问题中他没有使用并行流,我假设他正在尝试缓存 ConcurrentHashMap 中的值以便在任何其他时间使用它(为了线程安全操作),他的问题很简单:“这两个代码块有什么区别”
      • @Bolzano 我只是在学习 java 8 的流。目前根本不使用并行流。
      猜你喜欢
      • 2010-10-05
      • 2021-07-15
      • 2017-12-27
      • 1970-01-01
      • 1970-01-01
      • 2016-12-24
      • 2023-03-04
      • 2016-11-09
      相关资源
      最近更新 更多