一、线程池基础概念
为什么需要线程池:
- 复用线程资源,减少创建/销毁开销
- 控制并发线程数量,防止资源耗尽
- 统一管理任务队列和线程生命周期
二、Spring Boot线程池配置
1. 添加基础依赖(Spring Boot Starter Web)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. 配置线程池(推荐使用ThreadPoolTaskExecutor)
@Configuration
@EnableAsync // 启用异步支持
public class ThreadPoolConfig {
@Bean("taskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数(默认保持活跃的线程数)
executor.setCorePoolSize(5);
// 最大线程数(队列满后能创建的最大线程数)
executor.setMaxPoolSize(10);
// 队列容量(超过核心线程数时,新任务进入队列等待)
executor.setQueueCapacity(100);
// 线程名前缀
executor.setThreadNamePrefix("async-task-");
// 拒绝策略(当队列和最大线程都满时的处理方式)
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
3. application.yml配置(可选)
async:
thread:
core-pool-size: 5
max-pool-size: 10
queue-capacity: 100
三、使用线程池的4种业务场景
场景1:异步日志记录
@Service
public class LogService {
@Async("taskExecutor") // 指定使用哪个线程池
public void asyncAddLog(String logContent) {
// 模拟耗时操作
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 记录日志:" + logContent);
}
}
// 在Controller中使用
@RestController
public class LogController {
@Autowired
private LogService logService;
@GetMapping("/log")
public String log(){
logService.asyncAddLog("进来了");
return "成功";
}
}
场景2:批量数据处理(如Excel导入)
@Service
public class BatchProcessService {
@Async("taskExecutor")
public CompletableFuture<String> processDataChunk(List<Data> chunk) {
// 处理数据分片
chunk.forEach(data -> {
// 数据清洗、校验、存储等操作
});
return CompletableFuture.completedFuture("分片处理完成");
}
}
// 调用方示例
public void processAllData(List<Data> allData) {
// 将数据拆分为10个一组
List<List<Data>> chunks = Lists.partition(allData, 10);
List<CompletableFuture<String>> futures = chunks.stream()
.map(chunk -> batchProcessService.processDataChunk(chunk))
.collect(Collectors.toList());
// 等待所有任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
}
场景3:定时任务增强
@Slf4j
@Service
public class ScheduledService {
@Autowired
@Qualifier("taskExecutor")
private ThreadPoolTaskExecutor taskExecutor;
@Scheduled(cron = "0 0/5 * * * ?")
public void scheduledTask() {
// 将定时任务提交到线程池
taskExecutor.execute(() -> {
log.info("开始执行定时统计任务...");
// 执行耗时统计逻辑
});
}
}
场景4:高并发请求处理
@Service
public class PaymentService {
@Async("taskExecutor")
public CompletableFuture<Boolean> asyncPayment(PaymentRequest request) {
// 模拟支付处理
boolean success = paymentGateway.process(request);
return CompletableFuture.completedFuture(success);
}
}
// Controller中并发处理支付请求
@PostMapping("/batch-pay")
public ResponseEntity<?> batchPay(@RequestBody List<PaymentRequest> requests) {
List<CompletableFuture<Boolean>> futures = requests.stream()
.map(paymentService::asyncPayment)
.collect(Collectors.toList());
List<Boolean> results = futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
return ResponseEntity.ok(results);
}
四、关键配置参数说明
| 参数 | 说明 |
|---|---|
| corePoolSize | 核心线程数,即使空闲也不会被回收 |
| maxPoolSize | 最大线程数,当队列满时才会创建新线程 |
| queueCapacity | 任务队列容量,推荐使用有界队列防止内存溢出 |
| keepAliveSeconds | 非核心线程的空闲存活时间(秒) |
| RejectedPolicy | 拒绝策略(AbortPolicy-抛出异常/CallerRunsPolicy-用调用者线程执行) |
五、高级功能扩展
1. 添加基础依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2. 异常处理
@Configuration
public class AsyncExceptionConfig implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> {
System.err.println("异步任务异常:" + ex.getMessage());
System.err.println("方法名称:" + method.getName());
};
}
}
3. 线程池监控
// 暴露执行器端点
@Endpoint(id = "thread-pool")
@Component
public class ThreadPoolEndpoint {
@Autowired
@Qualifier("taskExecutor")
private ThreadPoolTaskExecutor executor;
@ReadOperation
public Map<String, Object> threadPoolStatus() {
return Map.of(
"activeCount", executor.getActiveCount(),
"poolSize", executor.getPoolSize(),
"queueSize", executor.getThreadPoolExecutor().getQueue().size()
);
}
}
// 在Controller中使用
@RestController
public class LogController {
@Autowired
private LogService logService;
@Autowired
private ThreadPoolEndpoint threadPoolEndpoint;
@GetMapping("/log")
public String log(){
logService.asyncAddLog("进来了");
return "成功";
}
@GetMapping("/log2")
public String log2(){
return JSON.toJSONString(threadPoolEndpoint.threadPoolStatus());
}
}
六、监控数据的使用场景
1. 实时诊断资源瓶颈
-
队列持续增长:说明处理速度跟不上任务提交速度:
- 增加
maxPoolSize - 优化任务处理逻辑
- 扩容服务器资源
- 增加
-
频繁触发拒绝策略:
- 调整
queueCapacity - 检查任务提交是否合理
- 调整
2. 动态调整参数(高级)
结合Spring Cloud Config实现动态调整:
@RefreshScope
@Bean
public ThreadPoolTaskExecutor taskExecutor(
@Value("${thread.pool.core-size:5}") int coreSize,
@Value("${thread.pool.max-size:10}") int maxSize
) {
// 创建线程池...
}
3. 设置报警规则(示例)
在Grafana中设置报警规则:
- 当
thread_pool_queue_size > 80持续5分钟时触发报警 - 当
thread_pool_rejected_total > 0时立即报警
通过以上方案,就全面掌握线程池的运行状态,及时发现并处理以下典型问题:
- 队列持续积压导致的延迟升高
- 线程资源耗尽导致的拒绝请求
- 配置参数不合理导致的资源浪费
七、生产环境最佳实践
-
监控指标选择:
- 必须监控:队列大小、活跃线程数、拒绝次数
- 建议监控:任务平均耗时、95分位耗时
-
安全控制:
management: endpoint: thread-pool: enabled: true endpoints: web: exposure: include: health,info,thread-pool server: port: 9001 # 与管理端口分离
八、常见问题排查
-
配置不生效:
- 检查是否添加了
@EnableAsync注解 - 确保异步方法在Spring管理的Bean中调用
- 检查是否添加了
-
线程池参数调优:
- CPU密集型任务:推荐线程数 = CPU核数 + 1
- IO密集型任务:推荐线程数 = CPU核数 * 2
-
资源耗尽问题:
- 监控队列堆积情况(queueSize)
- 合理设置拒绝策略
九、最佳实践建议
- 为不同业务类型配置独立的线程池(如订单线程池、日志线程池)
- 使用ThreadPoolTaskExecutor而不是直接使用Java原生线程池
- 生产环境建议开启线程池监控
- 合理设置任务超时时间
通过以上配置和示例代码,就可以在Spring Boot中高效地使用线程池来处理异步任务和并发请求。
实际使用时需要根据具体业务场景调整线程池参数,并通过监控持续优化。
感谢观看到这里,收藏一下,以后直接用吧,恭喜你又掌握或牢固了一个知识点。