Java 调整线程池大小

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 并将任务提交给它。
无论如何,在确定采用何种长期解决方案之前,请务必收集相关的性能数据。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程