1. 线程池的本质与价值
线程池这个看似简单的概念,背后隐藏着操作系统、并发编程和性能优化的多重智慧。我第一次在生产环境真正理解线程池的价值,是在某个用户量突然暴涨的深夜——当服务器日志开始疯狂报出"线程创建失败"的错误时,那个手动new Thread()的粗糙方案终于现出了原形。
现代操作系统创建一个线程的成本约为1MB内存和20ms时间。假设每秒有100个并发任务,直接创建线程的方案会瞬间耗尽资源。而线程池通过复用已创建的线程,将资源开销降低了一个数量级。这就是为什么Java的Executors框架、Go的goroutine调度器、Python的concurrent.futures都内置了线程池实现。
关键认知:线程池不是简单的线程集合,而是包含任务队列、线程管理、拒绝策略等完整生命周期的并发控制体系
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 线程池的四大核心组件
2.1 任务队列(Work Queue)
这个阻塞队列是线程池的缓冲地带,所有来不及处理的任务都在此排队。JDK提供了几种典型实现:
- LinkedBlockingQueue:无界队列(最大Integer.MAX_VALUE)
- ArrayBlockingQueue:固定大小队列
- SynchronousQueue:零容量队列(直接交接)
java复制// 典型的生产者-消费者模式
public void execute(Runnable task) {
if (poolSize < corePoolSize) {
addWorker(task); // 直接创建新线程
} else if (workQueue.offer(task)) {
// 入队成功
} else {
reject(task); // 触发拒绝策略
}
}
我在电商秒杀系统中曾犯过一个错误:使用了无界队列导致OOM。后来改用SynchronousQueue配合CallerRunsPolicy,当线程满载时让调用线程直接执行任务,完美解决了问题。
2.2 线程工厂(Thread Factory)
这个常被忽视的组件实际上关乎线上排查效率。好的线程工厂应该:
- 设置可识别的线程名前缀
- 标记是否为守护线程
- 设置合理的优先级
java复制class NamedThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger counter = new AtomicInteger(1);
public Thread newThread(Runnable r) {
Thread t = new Thread(r, namePrefix + "-" + counter.getAndIncrement());
t.setDaemon(false);
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
2.3 拒绝策略(Reject Policy)
当队列满且线程数达到maximumPoolSize时,这些策略决定如何处理新任务:
- AbortPolicy:直接抛出RejectedExecutionException(默认策略)
- CallerRunsPolicy:让调用线程执行任务
- DiscardPolicy:静默丢弃任务
- DiscardOldestPolicy:丢弃队列头部的任务
在支付系统中,我们自定义了日志记录+异步重试的混合策略:
java复制class RetryPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
log.warn("Task rejected, queuing for retry
