线程池-终极奥义 —— 程序员的奴隶工厂
核心思想:“宁可让线程累到猝死,也不让CPU闲着!”
1. 线程池七大参数(死亡轮盘)
ThreadPoolExecutor( int corePoolSize, // 正式工编制 int maximumPoolSize, // 临时工最大数量(含正式工) long keepAliveTime, // 临时工摸鱼时间(超时开除) TimeUnit unit, // 时间单位(比如:分钟摸鱼) BlockingQueue<Runnable> workQueue, // 任务候客区 ThreadFactory threadFactory, // 奴隶生成器 RejectedExecutionHandler handler // 拒绝策略(爆满时的骚操作)
)
暴力解读:
- 正式工(corePoolSize):就算没活干也得养着,池子的死忠粉
- 临时工(maximumPoolSize - corePoolSize):忙时扩招,闲时砍头
- 候客区(workQueue):
- ArrayBlockingQueue:有界队列,像医院挂号窗口(排满就炸)
- LinkedBlockingQueue:无界队列,像春运火车站(可能OOM)
- SynchronousQueue:直通队列,像打麻将“一缺三”(没有等待区)
2. 线程池工作流程(修罗场)
(以银行柜台为喻,代码级暴力拆解)
public void execute(Runnable command) { // 阶段1:正式工是否空闲? if (workerCount < corePoolSize) { if (addWorker(command, true)) // 创建正式工 return; } // 阶段2:扔到候客区排队 if (workQueue.offer(command)) { // 突然发现池子关了?(二次检查骚操作) if (isShutdown() && remove(command)) reject(command); else if (workerCount == 0) addWorker(null, false); // 保底一个临时工 } // 阶段3:连候客区都满了?召唤临时工! else if (!addWorker(command, false)) reject(command); // 彻底爆炸,执行拒绝策略
}
血腥流程:
- 来新任务先找正式工(corePool)
- 正式工满?丢到候客区(workQueue)
- 候客区爆满?紧急招聘临时工(maxPool)
- 连临时工都招满?启动拒绝策略大屠杀!
3. 拒绝策略(四大酷刑)
策略类 | 行为 | 现实比喻 |
---|---|---|
AbortPolicy | 直接抛RejectedExecutionException | “满了!滚!”(默认策略) |
CallerRunsPolicy | 让提交任务的线程自己执行 | “你自己没长手吗?” |
DiscardPolicy | 默默丢弃任务,装作无事发生 | 渣男行为(不拒绝不负责) |
DiscardOldestPolicy | 丢弃队列最老的任务,重试提交 | “老人就该死吗?”(社达主义) |
代码级处决现场:
// 自定义拒绝策略:记录日志+发告警
new ThreadPoolExecutor.AbortPolicy() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { log.error("他妈的任务炸了!", r); sendAlert("服务器要死了!"); throw new RejectedExecutionException("老子不干了!"); }
}
4. 线程池底层(黑暗解剖)
Worker类 —— 奴隶の枷锁
private final class Worker extends AbstractQueuedSynchronizer implements Runnable { final Thread thread; // 真正的苦力线程 Runnable firstTask; // 处女任务(可能为null) Worker(Runnable firstTask) { this.firstTask = firstTask; this.thread = getThreadFactory().newThread(this); // 工厂造人! } public void run() { runWorker(this); // 开启无限受虐循环 }
} final void runWorker(Worker w) { while (task != null || (task = getTask()) != null) { // 核心死亡循环! try { task.run(); // 执行任务(可能抛出异常) } finally { task = null; } }
}
黑暗秘密:
- 每个Worker包裹一个线程+一个初始任务
- 用AQS实现不可重入锁(防止任务中重复获取锁)
- getTask()方法从队列取任务时,会根据配置决定是否超时自杀
线程回收(断头台逻辑)
private Runnable getTask() { for (;;) { // 检查是否允许核心线程超时死亡 boolean timed = allowCoreThreadTimeOut || workerCount > corePoolSize; try { Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); // 阻塞直到有任务 if (r != null) return r; } catch (InterruptedException retry) {} // 超时后检查是否要自杀 if (workerCount > corePoolSize || allowCoreThreadTimeOut) return null; // return null触发worker死亡 }
}
5. 四种预定义线程池(作死指南)
1. newFixedThreadPool —— 铁饭碗工厂
Executors.newFixedThreadPool(10);
- 队列:LinkedBlockingQueue(无界)
- 风险:任务堆积直接OOM(OutOfMemoryError)
- 使用场景:已知任务量可控的稳定负载
2. newCachedThreadPool —— 临时工敢死队
Executors.newCachedThreadPool();
- 队列:SynchronousQueue(直接传递)
- 特点:线程数无上限,空闲60秒自杀
- 风险:瞬间创建大量线程导致CPU爆炸
- 使用场景:短命异步任务(比如HTTP请求)
3. newSingleThreadExecutor —— 寡头垄断
Executors.newSingleThreadExecutor();
- 本质:core=max=1的FixedThreadPool
- 队列:无界队列
- 使用场景:需要任务顺序执行(但依然有OOM风险)
4. newScheduledThreadPool —— 时间管理大师
Executors.newScheduledThreadPool(5);
- 特殊技能:定时任务(scheduleAtFixedRate)
- 底层:DelayedWorkQueue(按时间排序的堆结构)
- 坑爹点:异常会导致定时任务停止
线程池(作死圣经)
- 禁止用Executors创建线程池(容易OOM),推荐手动new ThreadPoolExecutor
- CPU密集型:核心线程数 ≈ CPU核数(避免过多上下文切换)
- IO密集型:核心线程数 ≈ CPU核数 * 2(比如数据库连接池)
- 队列选择原则:
- 要控制最大任务量 → ArrayBlockingQueue
- 要无限堆积 → LinkedBlockingQueue(准备好棺材)
- 要直接传递 → SynchronousQueue(配合maxPoolSize使用)
- 监控必备:继承ThreadPoolExecutor,重写beforeExecute/afterExecute
(掀桌子怒吼)现在!立刻!马上!给老子写个把CPU干到100%的线程池!