🌟 Spring Boot 多线程池统一配置与使用教程
本人通过以下类实现了多线程池的统一管理、异常安全包装、日志输出与监控:
TaskThreadPoolConfig.java
:多线程池配置类ExecutorBuilder.java
:通用线程池构建器ExceptionSafeRunnable.java
:线程任务异常封装器ThreadPoolMonitorUtils.java
:线程池状态监控工具application.yml
:集中配置参数
🧱 1. 配置文件 application.yml
thread-pool:
common:
core: 8 # 核心线程数
max: 16 # 最大线程数
queue: 200 # 队列容量
keepalive: 60 # 线程空闲时间 (秒)
prefix: "common-task-" # 线程前缀名
file:
core: 6
max: 12
queue: 200
keepalive: 120
prefix: "file-task-"
websocket:
core: 2
max: 4
queue: 50
keepalive: 30
prefix: "ws-task-"
schedule:
core: 2
max: 4
queue: 100
keepalive: 60
prefix: "schedule-task-"
🧩 2. 线程池构建器 ExecutorBuilder.java
⚠️ 这里使用了
new ThreadPoolExecutor.CallerRunsPolicy()
,ThreadPoolExecutor
是java的,并不是spring的,请注意。此方法为拒绝策略,拒绝策略自行搜索,本人使用的是CallerRunsPolicy()
,由调用线程处理该任务
import java.util.concurrent.ThreadPoolExecutor;
public class ExecutorBuilder {
public static ThreadPoolTaskExecutor build(
int corePoolSize,
int maxPoolSize,
int queueCapacity,
int keepAliveSeconds,
String threadNamePrefix
) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveSeconds);
executor.setThreadNamePrefix(threadNamePrefix);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
}
⚙️ 3. 多线程池配置类 TaskThreadPoolConfig.java
⚠️ 这里根据项目自行选择,个人建议不同操作可以分开管理,本人这里分了 4大类,主要使用了common和io,可以有限避免因为io操作慢导致其他操作不可用。
@Configuration
public class TaskThreadPoolConfig {
@Bean("commonTaskExecutor")
public ThreadPoolTaskExecutor commonTaskExecutor(
@Value("${thread-pool.common.core}") int core,
@Value("${thread-pool.common.max}") int max,
@Value("${thread-pool.common.queue}") int queue,
@Value("${thread-pool.common.keepalive}") int keepalive,
@Value("${thread-pool.common.prefix}") String prefix) {
return ExecutorBuilder.build(core, max, queue, keepalive, prefix);
}
@Bean("fileTaskExecutor")
public ThreadPoolTaskExecutor fileTaskExecutor(
@Value("${thread-pool.file.core}") int core,
@Value("${thread-pool.file.max}") int max,
@Value("${thread-pool.file.queue}") int queue,
@Value("${thread-pool.file.keepalive}") int keepalive,
@Value("${thread-pool.file.prefix}") String prefix) {
return ExecutorBuilder.build(core, max, queue, keepalive, prefix);
}
@Bean("websocketPushExecutor")
public ThreadPoolTaskExecutor websocketPushExecutor(
@Value("${thread-pool.websocket.core}") int core,
@Value("${thread-pool.websocket.max}") int max,
@Value("${thread-pool.websocket.queue}") int queue,
@Value("${thread-pool.websocket.keepalive}") int keepalive,
@Value("${thread-pool.websocket.prefix}") String prefix) {
return ExecutorBuilder.build(core, max, queue, keepalive, prefix);
}
@Bean("scheduleTaskExecutor")
public ThreadPoolTaskExecutor scheduleTaskExecutor(
@Value("${thread-pool.schedule.core}") int core,
@Value("${thread-pool.schedule.max}") int max,
@Value("${thread-pool.schedule.queue}") int queue,
@Value("${thread-pool.schedule.keepalive}") int keepalive,
@Value("${thread-pool.schedule.prefix}") String prefix) {
return ExecutorBuilder.build(core, max, queue, keepalive, prefix);
}
}
🛡 4. 异常安全封装器 ExceptionSafeRunnable.java
⚠️ 此方法是为了抛出异常,可不用
@Log4j2
public class ExceptionSafeRunnable implements Runnable {
private final Runnable task;
private final String taskName; // 可选,便于日志标识
public ExceptionSafeRunnable(Runnable task, String taskName) {
this.task = task;
this.taskName = taskName;
}
@Override
public void run() {
try {
task.run();
} catch (Throwable ex) {
// 统一异常处理逻辑
log.error("[线程异常] 任务: {},异常信息: {}", taskName, ex.getMessage(), ex);
}
}
public static Runnable wrap(Runnable task, String taskName) {
return new ExceptionSafeRunnable(task, taskName);
}
}
📊 5. 线程池监控工具类 ThreadPoolMonitorUtils.java
@Slf4j
public class ThreadPoolMonitorUtils {
/**
* 打印线程池运行状态
*
* @param executor 线程池
* @param name 线程池名称(用于日志标识)
*/
public static void printState(ThreadPoolTaskExecutor executor, String name) {
ThreadPoolExecutor pool = executor.getThreadPoolExecutor();
log.info("线程池 [{}] 状态:", name);
log.info(" - 核心线程数: {}", pool.getCorePoolSize());
log.info(" - 最大线程数: {}", pool.getMaximumPoolSize());
log.info(" - 当前活跃线程数: {}", pool.getActiveCount());
log.info(" - 当前任务数: {}", pool.getTaskCount());
log.info(" - 已完成任务数: {}", pool.getCompletedTaskCount());
log.info(" - 当前队列大小: {}", pool.getQueue().size());
log.info(" - 队列剩余容量: {}", pool.getQueue().remainingCapacity());
}
}
🚀 6. 启用异步支持(如使用 @Async)
在启动类或配置类添加:
@EnableAsync
@SpringBootApplication
public class Application { ... }
🧪 7. 使用示例
注入线程池:
@Resource(name = "commonTaskExecutor")
private ThreadPoolTaskExecutor commonExecutor;
提交任务(带异常封装):
commonExecutor.execute(ExceptionSafeRunnable.wrap(() -> {
// 异步任务内容
}, "业务处理任务"));
提交任务(无异常封装):
commonExecutor.execute( () -> {
// 异步任务内容
})
📡 8. 可选:定时打印线程池状态
⚠️ 这里可以自行扩展,可以通过接口、定时任务等使用
⚠️ 使用@Scheduled
请确保项目添加了@EnableScheduling
注解。
@Scheduled(fixedRate = 30000)
public void monitor() {
ThreadPoolMonitorUtils.printState(commonExecutor, "通用线程池");
}
✅ 总结推荐
推荐实践 | 建议说明 |
---|---|
拆分多线程池 | 根据业务类型独立配置,防止互相干扰 |
统一构建器 | 避免重复代码 |
异常封装器 | 所有任务包装为 ExceptionSafeRunnable ,防止吞异常 |
监控工具 | 开发/线上查看线程使用情况 |
@EnableAsync | 若使用 @Async ,必须开启 |