Q75: 线程池如何设计?任务如何调度?
核心结论
线程池的价值不是“把所有任务都扔进去并发跑”,而是给一类可并行任务提供受控的执行资源。
真正需要先设计的是:
- 哪些任务适合线程池
- 任务是 CPU 型还是 I/O 型
- 队列满了怎么办
- 执行顺序和优先级如何保证
如果这些边界不清晰,线程池很容易变成隐藏延迟和资源争用的黑盒。
一、线程池真正适合什么任务
常见更适合线程池的是:
- 后台 I/O
- 压缩和序列化
- 数据库任务
- 非实时统计和离线处理
不太适合直接扔进通用线程池的通常是:
- 强顺序状态机任务
- 需要单对象串行推进的逻辑
- 主战斗链路中的高一致性对象更新
二、线程池不是越大越好
线程数过多常见问题包括:
- 上下文切换增加
- 锁竞争加重
- cache locality 变差
- 线程空转
所以线程池大小通常应围绕:
- CPU 核数
- 任务类型
- 外部依赖阻塞比例
而不是“能开多少开多少”。
三、任务队列设计比线程数更关键
线程池系统通常真正容易出问题的不是线程,而是队列:
- 入队过快
- 出队跟不上
- 优先级混乱
- 长任务阻塞短任务
所以必须明确:
- 队列是否有界
- 是否分优先级
- 是否分不同任务类型独立队列
四、调度要先分清任务类型
1. CPU 型任务
更关注:
- 核心数利用
- 避免过度切换
2. I/O 型任务
更关注:
- 阻塞等待
- 超时控制
- 回调或结果投递
把这两类任务混在一个池里,经常会互相拖累。
五、结果回传路径也要设计
线程池不是“任务跑完就结束”,还要回答:
- 结果交给谁
- 是否切回主线程或拥有者线程
- 失败如何传播
如果这层不清晰,线程池只是在把复杂度往调用方甩。
六、工程上更稳妥的做法
常见做法是:
- 线程池按任务类型拆分
- 队列有界并带背压策略
- 长任务和短任务分离
- 结果统一回投到权威线程或事件循环
这样才能避免“池很忙,但系统更慢”的情况。
七、常见误区
1. 线程池就是并发提速器
不对。它只能提升适合并行的任务,不能替代边界清晰的并发设计。
2. 所有阻塞操作都丢线程池就行
如果没有限流和分级,只会把阻塞堆到另一个地方。
3. 一个全局线程池最简单
简单,但很容易让不同任务类型互相干扰。
参考资料
- 线程池调度、背压和异步任务回投实践资料
