背景

经过stream能够将一个一般的list,转化为流,然后就能够运用类似于管道的方法对list进行操作,假如咱们把stream换成parallelStream 依据字面上的意思,流会从串行 变成并行;既然是并行,就知道这里边必定会有线程安全问题,经过创建线程安全的List、Set,Map即可解决。

今日要说的一个问题,是parallelStream并行流功能的问题。咱们在运用了parallelStream并行处理的时分,发现并没有按照预期缩短批量任务履行的时刻。所以开端深入排查问题根源。

场景复现

下面的代码,咱们模仿复原了场景,开启了10个线程,这10个线程都在运用并行流进行数据核算。在履行的逻辑中,咱们让每个任务都sleep 1秒钟,这样就能够模仿一些I/O请求的耗时等候。

运用stream,程序会在20秒后回来,但咱们期望程序能够在1秒多回来,由于它是并行流,可是经过测验发现,咱们等了好久,任务才履行结束。

parallelStream并行流性能-踩坑集锦 28(一周一更)

原因分析

在不同的机器上履行,这段代码花费的时刻都不一样。既然是并行,那必定得有个并行度。太低了,表现不到并行的能才能; 太大了,又浪费了上下文切换的时刻。能够幻想一下假如在I/O密集型事务中用上parallelStream 会形成什么结果,所以要了解这个并行度,咱们需要检查具体的构造方法

在ForkJoinPool类中找到这样的代码

parallelStream并行流性能-踩坑集锦 28(一周一更)

能够看到,并行度究竟是多少,是由下面的参数来控制的。假如无法获取这个参数,则默许运用 CPU个数-1 的并行度。这个函数是为了核算密集型事务去设计的。假如你喂给它一大堆任务,它就会由并行履行退变成类似于串行的效 果。

解决方法

ForkJoinPool 并行数设置 方法一

parallelStream并行流性能-踩坑集锦 28(一周一更)
parallelism这个变量是final的,一旦设定,不允许修改。也就是说,上面的参数只会收效一次。

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");

留意:多个人设置不同的并行数 jvm加载类信息具体加载谁的值,那就不一定了。

ForkJoinPool 并行数设置 方法二

咱们能够经过供给外置的forkjoinpool,也就是改变提交方法,来完成不同类型的任务分离

parallelStream并行流性能-踩坑集锦 28(一周一更)

总结

一、不要在I/O密集型事务里 运用ParallelStream并行处理 功能会受影响

二、核算密集型事务里 能够考虑运用 并行数量设置 默许为当前机器CPU核数-1个