Java 8 的 parallelStream 中产生了多少线程?

Posted

技术标签:

【中文标题】Java 8 的 parallelStream 中产生了多少线程?【英文标题】:How many threads are spawned in parallelStream in Java 8? 【发布时间】:2015-08-28 10:16:09 【问题描述】:

在JDK8 中,当我使用parallelStream 时产生了多少个线程?比如在代码中:

list.parallelStream().forEach(/** Do Something */);

如果这个列表有 100000 个项目,会产生多少个线程?

另外,每个线程是否获得相同数量的项目来处理,还是随机分配的?

【问题讨论】:

***.com/questions/21163108/… @assylias 非常好的答案。 【参考方案1】:

Oracle 的并行流实现[1] 使用当前线程,除此之外,如果需要,还有构成默认 fork 连接池 ForkJoinPool.commonPool() 的线程,其默认大小等于CPU 的核心数。

可以使用此属性更改公共池的默认大小:

-Djava.util.concurrent.ForkJoinPool.common.parallelism=8

或者,您可以使用自己的池:

ForkJoinPool myPool = new ForkJoinPool(8);
myPool.submit(() ->
    list.parallelStream().forEach(/* Do Something */);
).get();

关于顺序,作业将在线程可用时立即执行,没有特定顺序。

正如@Holger 正确指出的那样,这是一个特定于实现的细节(文档底部只有one vague reference),这两种方法都适用于Oracle 的JVM,但绝对不能保证适用于其他供应商的JVM,该属性不能存在于非 Oracle 实现中,Streams 甚至无法在内部使用ForkJoinPool,从而基于ForkJoinTask.fork 的行为完全无用(see here 对此进行了详细说明)。

【讨论】:

也许值得补充的是,如果任务数量足够小,并行流实际上可能在主线程中运行。 需要注意的是,Stream API 对ForkJoinPool 的使用是一个实现细节。因此,这两种解决方案都适用于 Oracle 当前的实现,但不能保证在任何地方都适用。【参考方案2】:

虽然@uraimo 是正确的,但答案完全取决于“做某事”的作用。 parallel.streams API 使用有一些有趣问题的 CountedCompleter 类。由于 F/J 框架不使用单独的对象来保存结果,因此长链可能会导致 OOME。此外,那些长链有时会导致堆栈溢出。正如我在this article. 中指出的那样,这些问题的答案是使用 Paraquential 技术

另一个问题是使用嵌套并行 forEach 时创建的线程过多。

【讨论】:

以上是关于Java 8 的 parallelStream 中产生了多少线程?的主要内容,如果未能解决你的问题,请参考以下文章

java 8 parallelStream() 和 sorted()

带有 spring 注释方法的 Java .parallelStream()

组合器在 java parallelStream reduce 中的实际作用是啥

使用 parallelStream 时抛出 InterruptedException - Java [重复]

java并行之parallerlStream

深入浅出parallelStream