线程池饱和时三阶段流转为:核心线程→任务队列→最大线程;通过synchronousqueue(容量0)、corepoolsize=1、maxpoolsize=2及3个2秒任务,可清晰观测task-0在core线程、task-1触发扩容、task-2由main线程执行拒绝策略的全过程。

<p>用一段极简但有明确行为边界的代码,就能清晰观察线程池在饱和时的三阶段流转:核心线程 → 任务队列 → 最大线程(必要时)。</p> <h3>关键设计:让三阶段依次触发</h3> <p>不靠日志猜,而是用可验证的阻塞+计数方式,让每个阶段“显形”:</p>
- 用 SynchronousQueue(容量为0)——迫使新任务立刻尝试创建新线程,跳过排队,直触最大线程上限
- 设置 corePoolSize=1, maxPoolSize=2, keepAliveTime=1s —— 小而分明的边界
- 提交3个任务,每个任务 sleep(2s) —— 前两个会分别占住 core 和 max 线程;第三个因无空闲线程、又无法入队(SynchronousQueue 拒绝),触发拒绝策略
极简可运行代码(Java)
复制即跑,输出直接对应三阶段:
<code>ExecutorService pool = new ThreadPoolExecutor(
1, 2, 1, TimeUnit.SECONDS,
new SynchronousQueue(), // 关键:不缓存,逼出线程扩容
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝时由主线程执行,可见可测
);
// 提交3个长任务
IntStream.range(0, 3).forEach(i -> pool.submit(() -> {
System.out.println("Task-" + i + " running on " + Thread.currentThread().getName());
try { Thread.sleep(2000); } catch (InterruptedException e) {}
}));
pool.shutdown();
pool.awaitTermination(5, TimeUnit.SECONDS);
</code>
你将看到的明确流转证据
-
Task-0:在
pool-1-thread-1(核心线程)执行 → 核心线程启动 -
Task-1:在
pool-1-thread-2(非核心线程)执行 → 队列满(SynchronousQueue 拒绝入队),触发扩容至 max -
Task-2:由
main线程执行(CallerRunsPolicy)→ 饱和,拒绝策略生效,证实队列与线程均已达极限
换种队列再对比(验证“队列”角色)
把 SynchronousQueue 换成 new LinkedBlockingQueue(1):
- Task-0 → core 线程
- Task-1 → 入队(队列还有1空位)
- Task-2 → 队列满 → 扩容出 thread-2 执行
- Task-3 → 队列满 + 线程达 max → 拒绝 → main 执行
队列从“不存在”到“容量1”,输出线程名变化,就是队列在流转中真实参与的铁证。










