开发者社区 问答 正文

为什么parallelStream在将它们包装在ArrayList中,在可以工作时并没有运行?

哈希图具有两个键和值对,它们不会由不同的线程并行处理。

import java.util.stream.Stream;
import java.util.Map;
import java.util.HashMap;

class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        Map<String, Integer> map = new HashMap<>();
        map.put("a", 1);
        map.put("b", 2);
        map.values().parallelStream()
              .peek(x -> System.out.println("processing "+x+" in "+Thread.currentThread()))
              .forEach(System.out::println);
    }
}

输出:

processing 1 in Thread[main,5,main]
1
processing 2 in Thread[main,5,main]
2

网址:https://ideone.com/Hkxkoz

ValueSpliterator应该尝试将HashMap数组拆分为大小为1的插槽,这意味着应在不同的线程中处理两个元素。

来源:https : //www.codota.com/code/java/methods/java8.util.HMSpliterators $ ValueSpliterator /%3Cinit%3E

将它们包装后ArrayList,它会按预期工作。

new ArrayList(map.values()).parallelStream()
              .peek(x -> System.out.println("processing "+x+" in "+Thread.currentThread()))
              .forEach(System.out::println);

输出:

processing 1 in Thread[ForkJoinPool.commonPool-worker-3,5,main]
1
processing 2 in Thread[main,5,main]
2

展开
收起
垚tutu 2019-11-28 18:50:18 699 分享 版权
阿里云 AI 助理回答

在Java中,HashMap的并行流处理行为可能并不会如预期那样将每个元素分配到不同的线程中执行,尤其是当集合较小或者操作较快时。这是因为Java的Fork/Join框架(用于实现并行流)有一定的开销,对于小规模数据集,这个开销可能会超过并行处理带来的收益,因此它可能会选择不进行真正的并行处理,而是直接在主线程中顺序执行。

在您的示例中,直接对HashMap.values()使用parallelStream()时,两个值的处理都发生在同一个线程中,即主线程。这是因为默认的并行策略评估了任务的大小和复杂度后决定不进行拆分。

而当您将HashMap的值放入一个新的ArrayList后再进行并行流处理时,观察到了不同的行为,即两个元素分别在主线程和一个ForkJoinPool的工作线程中处理。这说明在这种情况下,集合转换为ArrayList后,其并行流的拆分策略或初始化条件导致了并行处理的发生。

需要注意的是,并行处理的确切行为会受到JVM的具体实现、运行时环境、可用处理器数量等多种因素的影响,因此并不保证每次都会得到相同的结果分布。此外,Java 8及之后版本中的并行流设计主要是为了利用多核CPU提高处理大规模数据集的效率,对于小规模数据,通常建议使用顺序流以减少并行开销。

如果您希望确保在阿里云产品环境中利用并行流高效且一致地处理数据,可以考虑以下几点:

  1. 数据量:确保数据集足够大,以使得并行处理的开销被处理速度的提升所抵消。
  2. 自定义拆分器:如果默认的拆分逻辑不满足需求,可以探索自定义 Spliterator 来更细粒度地控制数据的分割方式。
  3. 使用并发容器:虽然在这个例子中不适用,但在某些场景下,使用如ConcurrentHashMap这样的并发容器能更好地支持高并发下的读写操作。
  4. 环境配置:检查和调整JVM的并行参数,比如通过设置-Djava.util.concurrent.ForkJoinPool.common.parallelism来调整ForkJoinPool的并行度。
  5. 监控与调优:在阿里云ECS或容器服务等环境中,利用监控工具(如Arms)来观察应用性能,根据实际情况调整并行处理策略。

最后,考虑到实际应用中数据处理的复杂性和多样性,建议根据具体业务场景和性能测试结果来决定是否以及如何使用并行流。

有帮助
无帮助
AI 助理回答生成答案可能存在不准确,仅供参考
0 条回答
写回答
取消 提交回答
问答分类:
问答地址: