📚
🔍 核心知识体系
🚀 4种实现方案对比
方案 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
@Async注解 | 简单异步任务 | 零代码侵入 | 默认线程池不可控 |
ThreadPoolTaskExecutor | 需要精细控制线程池 | 完全可配置化 | 需要手动管理生命周期 |
CompletableFuture | 复杂异步编排 | 函数式编程友好 | 学习曲线较高 |
并行流(parallelStream) | 集合数据处理 | 语法简洁 | 不适合IO密集型任务 |
💻 核心代码示例
1. 基础@Async配置
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
@Service
public class EmailService {
@Async("taskExecutor")
public CompletableFuture<String> sendEmail(String content) {
// 模拟耗时操作
Thread.sleep(2000);
return CompletableFuture.completedFuture("Email sent: " + content);
}
}
2. CompletableFuture组合
public ProductDetail getProductDetail(Long id) {
CompletableFuture<Product> productFuture = CompletableFuture
.supplyAsync(() -> productService.getProduct(id), taskExecutor);
CompletableFuture<Inventory> inventoryFuture = CompletableFuture
.supplyAsync(() -> inventoryService.getStock(id), taskExecutor);
return productFuture.thenCombineAsync(inventoryFuture, (product, inventory) -> {
ProductDetail detail = new ProductDetail();
detail.setProduct(product);
detail.setInventory(inventory);
return detail;
}, taskExecutor).join();
}
🛠️ 线程池监控方案
1. Actuator端点配置
management:
endpoints:
web:
exposure:
include: threadpool
2. 自定义监控指标
@Bean
public MeterBinder taskExecutorMetrics(ThreadPoolTaskExecutor executor) {
return (registry) -> {
Gauge.builder("thread.pool.active", executor::getActiveCount)
.register(registry);
Gauge.builder("thread.pool.queue.size", executor::getQueueSize)
.register(registry);
};
}
⚠️ 常见坑与解决方案
- 异步失效问题
- 原因:在同一个类中调用@Async方法
- 方案:通过AopContext.currentProxy()获取代理对象
- 线程上下文丢失
executor.setTaskDecorator(runnable -> {
RequestAttributes context = RequestContextHolder.currentRequestAttributes();
return () -> {
try {
RequestContextHolder.setRequestAttributes(context);
runnable.run();
} finally {
RequestContextHolder.resetRequestAttributes();
}
};
});
- 问题:SecurityContext/ThreadLocal信息传递
- 方案:配置TaskDecorator
- OOM风险
- 现象:无界队列导致内存溢出
- 方案:合理设置队列容量+拒绝策略
📖 推荐学习资源
- 官方文档
Spring Task Execution and Scheduling - 深度解析博客
美团技术团队-线程池最佳实践 - 实战项目案例
GitHub搜索关键词:
spring-boot async thread-pool
spring-boot completablefuture example
掌握这些内容后,可以尝试实现:
✅ 电商秒杀系统的库存扣减
✅ 大数据量的并行批处理
✅ 第三方API的并发调用优化
实战
📚 多线程开发案例详解
案例1:电商订单异步处理系统
场景描述
当用户下单后需要同时处理:
- 库存扣减
- 发送短信通知
- 生成物流单号
使用多线程实现并行处理,提升接口响应速度
代码实现
// 配置自定义线程池
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean("orderTaskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 常驻核心线程数(类似银行固定开放窗口)
executor.setMaxPoolSize(10); // 最大线程数(业务高峰时新增的临时窗口)
executor.setQueueCapacity(50); // 等待队列容量(客户等待区座位数)
executor.setThreadNamePrefix("Order-Async-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); // 拒绝策略
executor.initialize();
return executor;
}
}
// 业务服务类
@Service
public class OrderService {
@Autowired
private InventoryService inventoryService;
@Autowired
private SmsService smsService;
@Autowired
private LogisticsService logisticsService;
@Async("orderTaskExecutor")
public CompletableFuture<Void> processOrderAsync(Order order) {
// 并行执行三个任务
CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> {
inventoryService.deductStock(order.getProductId(), order.getQuantity());
}, taskExecutor);
CompletableFuture<Void> task2 = CompletableFuture.runAsync(() -> {
smsService.sendOrderConfirm(order.getUserPhone(), order.getId());
}, taskExecutor);
CompletableFuture<Void> task3 = CompletableFuture.runAsync(() -> {
logisticsService.generateTrackingNumber(order.getId());
}, taskExecutor);
// 等待所有任务完成
return CompletableFuture.allOf(task1, task2, task3);
}
}
代码解析
ThreadPoolTaskExecutor
配置详解:- 核心线程数5:始终保持5个线程待命
- 最大线程数10:当队列满时最多创建10个线程
- 队列容量50:允许堆积50个等待任务
- 拒绝策略AbortPolicy:超出处理能力时直接抛出异常
CompletableFuture.allOf()
方法:- 实现多个异步任务的并行执行
- 所有任务完成后返回复合Future
- 可通过
join()
阻塞等待全部完成
- 异常处理建议:
task1.exceptionally(ex -> {
log.error("库存扣减失败", ex);
return null;
});
案例2:大数据文件分片处理
场景描述
处理10万行CSV文件,每100行为一个分片,多线程并行处理
代码实现
public void processLargeFile(String filePath) {
List<String> allLines = Files.readAllLines(Paths.get(filePath));
int batchSize = 100;
// 分片处理
AtomicInteger counter = new AtomicInteger(0);
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i=0; i<allLines.size(); i+=batchSize) {
List<String> batch = allLines.subList(i, Math.min(i+batchSize, allLines.size()));
futures.add(processBatchAsync(batch, counter));
}
// 等待所有分片完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.join();
}
@Async
public CompletableFuture<Void> processBatchAsync(List<String> batch, AtomicInteger counter) {
return CompletableFuture.runAsync(() -> {
batch.forEach(line -> {
// 模拟数据处理
DataModel model = parseLine(line);
repository.save(model);
counter.incrementAndGet();
});
}).exceptionally(ex -> {
log.error("批次处理失败", ex);
return null;
});
}
执行流程
性能优化技巧
- 线程池参数计算公式
// 最佳线程数 ≈ CPU核心数 * (1 + 等待时间/计算时间)
int coreSize = Runtime.getRuntime().availableProcessors() * 2;
executor.setCorePoolSize(coreSize);
- 监控关键指标
// 在Micrometer中监控
Metrics.gauge("threadpool.active", executor, ThreadPoolTaskExecutor::getActiveCount);
Metrics.gauge("threadpool.queue", executor, e -> e.getThreadPoolExecutor().getQueue().size());
- 上下文传递方案对比
方案 | 优点 | 缺点 |
---|---|---|
TaskDecorator | 官方推荐,无侵入 | 需手动复制上下文 |
MDC | 日志追踪方便 | 只适用于日志场景 |
参数透传 | 明确直观 | 增加方法参数 |
通过这两个典型案例,可以掌握:
✅ 线程池的合理配置
✅ CompletableFuture的进阶用法
✅ 大数据量并行处理方案
✅ 生产环境中的异常处理技巧
✅ 性能监控与调优方法