Java 调整线程池大小,用户希望在通用线程池中自定义线程数量,而不是使用默认大小的线程池。适当调整系统参数,或将任务提交到自定义的 ForkJoinPool
实例。
Java 调整线程池大小 问题描述
用户希望在通用线程池中自定义线程数量,而不是使用默认大小的线程池。
Java 调整线程池大小 解决方案
适当调整系统参数,或将任务提交到自定义的 ForkJoinPool
实例。
Java 调整线程池大小 具体实例
根据 Javadoc 对 java.util.concurrent.ForkJoinPool
类的描述,可以通过以下三种系统属性控制通用线程池的构建:
java.util.concurrent.ForkJoinPool.common.parallelism
-
java.util.concurrent.ForkJoinPool.common.threadFactory
-
java.util.concurrent.ForkJoinPool.common.exceptionHandler
之前曾经提到过,默认情况下,通用线程池大小等于 JVM 上可用的处理器数量,它由 Runtime.getRuntime().availableProcessors()
确定。parallelism
标志用于指定并行级别(parallelism level),它是一个非负整数,可以通过编程方式或命令行方式来设置。例 9-12 显示了如何采用 System.setProperty
方法创建所需的并行级别。
例 9-12 采用编程方式设置通用线程池大小
System.setProperty(
"java.util.concurrent.ForkJoinPool.common.parallelism", "20");
long total = LongStream.rangeClosed(1, 3_000_000)
.parallel()
.sum();
int poolSize = ForkJoinPool.commonPool().getPoolSize();
System.out.println("Pool size: " + poolSize); ➊
➊ 打印 Pool size: 20
将通用线程池大小设置为大于可用的 CPU 核心数无助于性能提升。
在命令行中,可以像使用任何系统属性一样使用 -D
标志。请注意,编程设置将覆盖命令行设置,如例 9-13 所示。
例 9-13 采用系统参数设置通用线程池大小
$ java -cp build/classes/main concurrency.CommonPoolSize
Pool size: 20
// 注释掉System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");
$ java -cp build/classes/main concurrency.CommonPoolSize
Pool size: 7
$ java -cp build/classes/main \
-Djava.util.concurrent.ForkJoinPool.common.parallelism=10 \
concurrency.CommonPoolSize
Pool size: 10
本例在一台 8 核计算机上运行。默认的线程池大小为 7,但如果将 main
线程包括在内,则默认情况下共有 8 个活动线程。
自定义ForkJoinPool
ForkJoinPool
类定义了一个构造函数,它传入一个整数作为并行级别。我们可以借此创建有别于通用线程池的自定义线程池,并将任务提交给它。
例 9-14 显示了如何创建自定义线程池。
例 9-14 创建自定义
ForkJoinPool
ForkJoinPool pool = new ForkJoinPool(15); ➊
ForkJoinTask<Long> task = pool.submit( ➋
() -> LongStream.rangeClosed(1, 3_000_000)
.parallel()
.sum());
try {
total = task.get(); ➌
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
pool.shutdown();
}
poolSize = pool.getPoolSize();
System.out.println("Pool size: " + poolSize); ➍
❶ 实例化一个大小为 15 的 ForkJoinPool
❷ 提交 Callable<Long>
作为任务
❸ 执行任务并等待回复
❹ 打印 Pool size: 15
大部分情况下,在流上调用 parallel
方法时所用的通用线程池都能满足要求。如果需要改变其大小,请调整系统属性;如果仍然无法满足要求,请尝试创建自定义 ForkJoinPool
并将任务提交给它。
无论如何,在确定采用何种长期解决方案之前,请务必收集相关的性能数据。