线程创建成本高,队列扩容轻量,故需队列满才扩容线程以避免频繁创建销毁开销;核心线程数应匹配cpu负载,防止过载与无效竞争;队列仅作短时缓冲,满则表明系统临界需临时增援;不同场景策略不同,如tomcat用synchronousqueue即时扩容应对io密集型请求。
因为线程是昂贵资源,而队列只是内存;等队列真满了再扩容线程,是为了避免频繁创建销毁带来的开销和上下文切换损耗。
线程创建成本远高于入队操作
新建一个线程要分配栈空间、注册内核对象、触发用户态/内核态切换,这些操作耗时远超把任务塞进队列。队列用的是堆内存,便宜又轻量。如果一有积压就加线程,遇到脉冲流量(比如秒杀瞬间涌来几百请求),系统可能反复创建销毁几十个线程——光调度开销就压垮CPU,任务反而更慢。
防止 CPU 过载和无效竞争
核心线程数通常按 CPU 核心数或负载经验设定,目标是让 CPU 保持高利用率但不过载。如果 CPU 已被核心线程占满,此时再盲目加线程,不会加快处理速度,只会增加上下文切换次数,导致所有线程都卡在“抢时间片”上,吞吐量不升反降。
队列本质是缓冲,不是长期仓库
设计上,队列只用来应对短时抖动。理想状态是:任务进来马上被核心线程取走,队列里几乎没积压。一旦队列满了,说明核心线程持续忙、缓冲已失效,这时才需要“临时增援”——也就是非核心线程。这不是为了优先处理新任务,而是因为系统已到临界点,必须扩容否则就要丢任务。
不同场景策略其实不一样
标准 ThreadPoolExecutor 是“队列满才扩容”,但像 Tomcat 这类 Web 容器做了定制:它用 SynchronousQueue(容量为 0),任务根本进不了队列,只要核心线程忙、且线程数未达上限,就立刻创建新线程。这是因为它面向 IO 密集型请求——线程大部分时间在等网络或数据库,CPU 有空闲,不扩容反而浪费资源、拉长用户响应时间。










