- CPU 密集型 :任务大量消耗 CPU,几乎无等待。 核心思路:减少线程数量,减少上下文切换
核心公式:
核心线程数 = CPU核心数 + 1+1 是为了防止某个线程偶尔页缺失 / 临时暂停,让这个备用线程顶上去,充分利用 CPU。
- IO 密集型 :任务大部分时间在等待网络、数据库、文件 IO,CPU 空闲。 核心思路:多开线程,利用等待时间处理别的任务
核心公式:
核心线程数 = CPU核心数 * (1 + IO等待时间 / CPU计算时间)经验估算简化:
2 * CPU核心数,业务 IO 阻塞严重时可以给到CPU 核心数 * 5~10,根据压测调优。
⚠️ 重点:公式只是理论参考!最终一定要压测调整,不能直接硬套。
详细解释
1. CPU 密集型
- 特点:大量计算,几乎没有 IO 等待,CPU 一直在跑。
- 如果线程开太多:多个线程频繁抢占 CPU,上下文切换开销很大,性能下降。
- 推荐:核心线程数 ≈ CPU 核心数 +1
- 例子:4 核 CPU,核心线程设置为 5。
2. IO 密集型(后端开发最常见,数据库、RPC、文件读写)
- 特点:线程大部分时间阻塞等待 IO,CPU 是空闲的。
- 线程多一点没关系,当一个线程等待 DB 返回,其他线程可以继续执行。
- 公式理解:
IO等待时间 / CPU计算时间是等待占比。 比如:任务执行总共 1000ms,其中计算 100ms,等待 DB900ms。CPU核心数*(1+900/100)= 核心数*10 - 经验值:一般 2 倍 CPU 核心起步;IO 阻塞很高,可放大到 5~10 倍,但是不能无限大,线程太多会占用大量内存,数据库连接池、连接数也会打满,造成雪崩。
相关问题
Q:为什么 IO 密集不能无限加大线程?
A:线程本身占用内存;线程过多,操作系统上下文切换开销上升;同时下游资源(数据库连接、第三方接口)都有最大连接上限,线程太多会把下游打垮。
Q:线程池的核心参数有哪些?
ThreadPoolExecutor 7 个参数:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:非核心线程空闲存活时间
- unit:时间单位
- workQueue:阻塞队列,存放等待任务
- threadFactory:线程工厂,创建线程
- handler:拒绝策略,任务满了之后的处理策略
Q:四种拒绝策略?
- AbortPolicy:抛异常(默认)
- DiscardPolicy:直接丢弃任务,不抛异常
- DiscardOldestPolicy:丢弃队列最老任务,再尝试提交
- CallerRunsPolicy:交给调用者线程执行(不会丢任务,降级)
一句话总结
CPU 密集型,核心线程数设置为 CPU 核心数 + 1,减少上下文切换;
IO 密集型可以设置更大,参考CPU核心*(1+IO等待时间/计算时间),经验值 2~10 倍 CPU 核心;
公式仅理论,最终必须压测验证。