⚡️CPU:JAVA King为窝发声,HELP ME⚡️
想象一下:每次点外卖都新雇一个厨师,吃完就开除——这就是裸奔线程的日常!在高并发三巨头(电商秒杀、金融交易、大数据处理)中:
1️⃣ CPU哭诉:90%时间在面试线程,10%干活(线程切换开销)
2️⃣ 内存抗议:无限招人导致办公室挤爆(OOM崩溃)
3️⃣ 用户怒骂:响应比蜗牛还慢
在电商秒杀、金融交易、大数据处理等高并发场景中,频繁创建/销毁线程会导致
1️⃣ CPU资源浪费(线程切换开销)
2️⃣ 内存溢出风险(无限制创建线程)
3️⃣ 响应延迟(线程初始化耗时)
线程池 = 智能HR总监:复用老员工 + 弹性扩缩容 + 拒绝996福报!
案例:用户注册后异步发送邮件/短信
// 配置线程池(Spring Boot)
@Configuration
public class ThreadPoolConfig {
@Bean("taskExecutor")
public Executor asyncExecutor() {
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 UserService {
@Autowired
private EmailService emailService;
@Async("taskExecutor") // Spring异步注解
public void sendWelcomeEmail(User user) {
emailService.send(user.getEmail(), "Welcome!");
}
public void register(User user) {
saveUser(user); // 同步:保存用户
sendWelcomeEmail(user); // 异步:非阻塞发送邮件
}
}
关键点:
@Async
注解实现非阻塞调用CallerRunsPolicy
:当队列满时,由调用线程执行任务(降级策略)案例:批量导出10万条订单数据为Excel
public class OrderExportService {
private static final int BATCH_SIZE = 1000;
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
8, // corePoolSize
16, // maxPoolSize
60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(500), // 有界队列防OOM
new CustomThreadFactory("OrderExport-"),
new ThreadPoolExecutor.AbortPolicy()
);
public void exportOrders(List<Order> orders) {
List<CompletableFuture<Void>> futures = new ArrayList<>();
// 数据分片
List<List<Order>> batches = Lists.partition(orders, BATCH_SIZE);
for (List<Order> batch : batches) {
futures.add(CompletableFuture.runAsync(() -> {
exportBatchToExcel(batch); // 并行处理每个批次
}, executor));
}
// 等待所有任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])
.join();
}
private void exportBatchToExcel(List<Order> batch) {
// 实际导出逻辑...
}
}
关键点:
CompletableFuture.runAsync
提交并行任务CustomThreadFactory
命名线程(日志排查友好)案例:每天凌晨统计昨日销售额
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
// 每天00:05执行
scheduler.scheduleAtFixedRate(() -> {
salesReportService.generateDailyReport();
}, calculateInitialDelay(), 24, TimeUnit.HOURS);
private long calculateInitialDelay() {
LocalDateTime now = LocalDateTime.now();
LocalDateTime nextRun = now.withHour(0).withMinute(5).plusDays(1);
return Duration.between(now, nextRun).toMillis();
}
优势 vs Timer:
Executors.newCachedThreadPool()
ThreadPoolExecutor
,明确指定队列容量AbortPolicy
抛异常!// 根据业务选择策略:
new ThreadPoolExecutor.CallerRunsPolicy() // 由调用线程执行
new CustomRetryPolicy() // 自定义重试逻辑
// 获取线程池状态
executor.getActiveCount(); // 活动线程数
executor.getQueue().size(); // 队列积压量
executor.getCompletedTaskCount(); // 已完成任务数
需求:高峰时段扩容线程数,低谷时缩容
ThreadPoolExecutor executor = ... ;
// 动态调整核心线程数
executor.setCorePoolSize(20); // 高峰扩容
// 动态调整最大线程数
executor.setMaximumPoolSize(30);
配合Spring Cloud Config/Nacos实现运行时配置热更新!
线程池是Java高并发编程的基石,正确使用能带来:
记住黄金法则:
- 永远手动创建线程池(禁用Executors快捷方法)
- 队列必须有界(除非确信任务量可控)
- 拒绝策略必须适配业务
附录:线程池参数速查表
参数 | 说明 | 推荐值 |
---|---|---|
corePoolSize | 核心线程数(长期存活) | CPU密集型:N+1,I/O密集型:2N |
maxPoolSize | 最大线程数(临时扩容) | 根据压测结果动态调整 |
workQueue | 任务队列 | ArrayBlockingQueue (有界) |
keepAliveTime | 非核心线程空闲存活时间 | 30-60秒 |
handler | 拒绝策略 | CallerRunsPolicy (保底) |
⚡️JAVA King:我来了⚡️
⚡️线程池:嘿嘿嘿,JAVA KING你来晚了⚡️
⚡️CPU:OH,YES YES⚡️