我可以重现您所看到的行为,其中并行性与您指定的 fork-join 池并行性的并行性不匹配。将 fork-join 池并行度设置为 10,并将集合中的元素数量增加到 50 后,我发现基于列表的流的并行度仅上升到 6,而基于集合的流的并行度永远不会超过2.
但请注意,这种将任务提交到 fork-join 池以在该池中运行并行流的技术是一种实现“技巧”,并且不保证上班。事实上,用于执行并行流的线程或线程池是未指定。默认情况下,使用通用的fork-join池,但在不同的环境中,可能最终会使用不同的线程池。 (考虑应用程序服务器内的容器。)
In the java.util.stream.AbstractTask http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/jdk8-b132/src/share/classes/java/util/stream/AbstractTask.java类,该LEAF_TARGET
字段决定了所完成的分割量,进而决定了可以实现的并行度。该字段的值基于ForkJoinPool.getCommonPoolParallelism()
当然,它使用公共池的并行性,而不是恰好运行任务的任何池。
可以说这是一个错误(请参阅 OpenJDK 问题JDK-8190974 https://bugs.openjdk.java.net/browse/JDK-8190974),但是,无论如何,整个区域都未指定。然而,系统的这个领域肯定需要发展,例如在拆分策略、可用并行度、处理阻塞任务等方面。 JDK 的未来版本可能会解决其中一些问题。
同时,可以通过使用系统属性来控制公共fork-join池的并行性。如果您将此行添加到您的程序中,
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "10");
并且您在公共池中运行流(或者如果您将它们提交到您自己的具有足够高并行度集的池),您将观察到更多任务正在并行运行。
您还可以使用命令行在命令行上设置此属性-D
option.
同样,这不是保证的行为,并且将来可能会改变。但在可预见的将来,这种技术可能适用于 JDK 8 实现。
2019 年 6 月 12 日更新:错误JDK-8190974 https://bugs.openjdk.java.net/browse/JDK-8190974已在 JDK 10 中修复,并且该修复已向后移植到即将发布的 JDK 8u 版本 (8u222)。