Java 8中的parallelStream会生成多少个线程?

124
在使用parallelStream时,在JDK8中会生成多少线程?例如,对于以下代码:
list.parallelStream().forEach(/** Do Something */);

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

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


8
https://dev59.com/r2Ei5IYBdhLWcg3wjs5j#21172732 - assylias
@assylias 真的是非常好的回答。 - uraimo
2个回答

128

Oracle的并行流实现[1]使用当前线程,如果需要,还会使用组成默认ForkJoinPool ForkJoinPool.commonPool()的线程,该池的默认大小等于CPU核心数减一。

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

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

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

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

关于顺序,作业将在线程可用时立即执行,没有特定的顺序。
正如@Holger所指出的那样,这是一个实现细节(只有文档底部的一个模糊的参考),两种方法都适用于Oracle的JVM,但绝对不能保证在其他供应商的JVM上工作,该属性可能在非Oracle实现中不存在,并且流甚至可能不使用ForkJoinPool来内部渲染基于ForkJoinTask.fork行为的替代方案完全无用(在此处查看详情)。

7
如果任务数量足够小,可能值得补充说明的是并行流实际上会在主线程中运行。 - assylias
18
需要翻译的内容:It should be noted that the Stream APIs use of ForkJoinPool is an implementation detail. Thus, both solutions work with Oracle’s current implementation but are not guaranteed to work everywhere.翻译后:需要注意的是,Stream API 使用 ForkJoinPool 是一项实现细节。因此,这两种解决方案适用于 Oracle 的当前实现,但不能保证在所有情况下都能奏效。 - Holger
5
似乎在这里进行过载会很有意义--parallelStream(int maxDegreeOfParallelism)--你知道,就像我们在C#中所拥有的那样。 - Josh M.

5
虽然@uraimo是正确的,但答案取决于“Do Something”具体做什么。parallel.streams API使用CountedCompleter类,它存在一些有趣的问题。由于F/J框架不使用单独的对象来保存结果,长链可能导致OOME。此外,这些长链有时会导致堆栈溢出。解决这些问题的方法是使用我在这篇文章中指出的Paraquential技术。
另一个问题是在使用嵌套并行forEach时会产生过多的线程创建。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接