1. Java 线程池优化

1.1. 核心线程数

  • CPU 密集型线程池计算公式:
核心线程数 = CPU 核心数 + 1
  • IO 密集型线程池计算公式:
核心线程数 = ((线程等待时间 + 线程 CPU 时间)/线程 CPU 时间)* CPU 数目

1.2. 任务队列

java.util.concurrent.BlockingQueue 的子类大多可作为任务队列,但一般使用 java.util.concurrent.ArrayBlockingQueuejava.util.concurrent.LinkedBlockingQueuejava.util.concurrent.SynchronousQueue 作为任务队列。

1.2.1. LinkedBlockingQueue

基于链表的阻塞队列。

调用 LinkedBlockingQueue(int capacity) 构建方法指定队列大小时,作为有界任务队列。

调用 LinkedBlockingQueue() 无参构建方法时,等价于 LinkedBlockingQueue(Integer.MAX_VALUE),队列大小为 2147483647,一般任务数量达到这个数值时,程序已经 OOM 了,所以相当于无界任务队列,本质上还是有界任务队列。

1.2.2. ArrayBlockingQueue

基于数组的阻塞队列。构造方法必须指定队列大小,是有界任务队列。

1.2.3. SynchronousQueue

队列大小为 0 的阻塞队列,添加到队列的任务将立即被处理,当所有核心线程处于活动状态,线程池将新建新的线程来处理任务,直至达到最大线程数。

1.2.4. 总结

一般使用 ArrayBlockingQueue 有界阻塞队列,队列大小视实际情况而定,一般取 10000

1.3. 最大线程数

当所有核心线程均处于活动状态,并且任务队列已满,线程池才会新建新的线程来处理任务,直至所有线程达到最大线程数。

最大线程数视实际情况而定,一般取核心线程数 * 2

1.4. 线程存活时间

视实际情况而定,一般一分钟

1.5. 拒绝策略

当任务队列已满,并且线程池已达到最大线程数量时,提交任务到线程池将被拒绝。Java 定义了 4 种拒绝策略。

1.5.1. AbortPolicy(默认策略)

抛出 RejectedExecutionException 来拒绝新提交的任务。

1.5.2. CallerRunsPolicy

调用者所在的线程会尝试执行被拒绝的任务。

1.5.3. DiscardPolicy

不采取任何措施,丢弃无法处理的任务。

1.5.4. DiscardOldestPolicy

丢弃队列最前面的任务,然后尝试再次提交被拒绝的任务。

1.5.5. 总结

重要数据处理任务使用 CallerRunsPolicy,避免数据丢失。或者使用 AbortPolicy,并做好异常善后处理。

1.6. 最终优化代码

import cn.hutool.core.thread.ExecutorBuilder;
import cn.hutool.core.thread.ThreadUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Configuration
public class ThreadPoolConfiguration {
    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        return ExecutorBuilder.create()
                .setCorePoolSize(availableProcessors * 50)
                .setMaxPoolSize(availableProcessors * 100)
                .setKeepAliveTime(1L, TimeUnit.MINUTES)
                .useArrayBlockingQueue(10_000)
                .setHandler(new ThreadPoolExecutor.CallerRunsPolicy())
                .setThreadFactory(ThreadUtil.createThreadFactory("my-thread-"))
                .build();
    }
}

Jason
4 声望0 粉丝