当前位置: 首页 > news >正文

线程池核心线程数设为 0 会怎样?(附源码解析)

不知道大家学习线程池时有没有这个疑问,创建线程池时如果用的无界队列(或者比较大的队列),核心线程数设置为 0,按照网上说的线程池的任务执行流程,队列不满不会创建非核心线程,那不炸了吗?任务永远执行不了?

网上普遍的线程池工作流程图:

先说结论

即使核心线程数设置为 0,提交一个任务后线程池也会创建一个线程去执行。

代码验证

核心线程数为 0,线程池中会创建一个线程,任务会由这个线程顺序执行

public static void main(String[] args) throws InterruptedException { // 配置:核心 0,最大 5,存活 60 秒 ThreadPoolExecutor executor = new ThreadPoolExecutor( 0, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100) ); // 提交 10 个任务 for (int i = 0; i < 10; i++) { int cur = i; executor.execute(() -> { System.out.println(cur +"执行,线程:" + Thread.currentThread().getName()); }); } }

为了更加清楚执行过程中线程池的情况:

public static void main(String[] args) throws InterruptedException { // 配置:核心 0,最大 5,存活 60 秒 ThreadPoolExecutor executor = new ThreadPoolExecutor( 0, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100) ); // 提交 3 个任务 for (int i = 0; i < 3; i++) { int cur = i; executor.execute(() -> { System.out.println(cur + "执行,线程:" + Thread.currentThread().getName()); try { Thread.sleep(500); // 模拟任务执行时间 } catch (InterruptedException e) { throw new RuntimeException(e); } }); // 打印当前线程池状态 System.out.println("=== 提交任务 " + i + " 后 ==="); System.out.println("核心线程数:" + executor.getCorePoolSize()); System.out.println("最大线程数:" + executor.getMaximumPoolSize()); System.out.println("当前线程数:" + executor.getPoolSize()); System.out.println("活跃线程数:" + executor.getActiveCount()); System.out.println("队列大小:" + executor.getQueue().size()); System.out.println("完成任务数:" + executor.getCompletedTaskCount()); System.out.println("========================\n"); Thread.sleep(1000); } // 等待所有任务完成 Thread.sleep(3000); System.out.println("\n=== 最终状态 ==="); System.out.println("当前线程数:" + executor.getPoolSize()); System.out.println("活跃线程数:" + executor.getActiveCount()); System.out.println("队列大小:" + executor.getQueue().size()); System.out.println("完成任务数:" + executor.getCompletedTaskCount()); }

可以看出线程池中始终只有一个线程在处理任务

正常情况下,设置核心线程数为 2,会有两个线程会并发执行。

public static void main(String[] args) throws InterruptedException { // 配置:核心 2,最大 5,存活 60 秒 ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100) ); // 提交 10 个任务 for (int i = 0; i < 10; i++) { int cur = i; executor.execute(() -> { System.out.println(cur +"执行,线程:" + Thread.currentThread().getName()); }); } }

源码分析(debug)

一层层扒开源码看一下整个流程。
  1. 任务提交时,可以看到线程池无线程

  1. 走到 execute 方法里面,这时可以队列中加入一个任务,接着会走进workerCountOf(recheck) == 0这个判断里(即线程数为 0),这是个兜底策略,针对核心线程数为 0 的特殊情况

execute源码:

public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command); }
  1. 进入addWorker 方法,就可以看到这里会创建一个线程去执行任务,可以看到线程数为 1

addWorker 源码:

private boolean addWorker(Runnable firstTask, boolean core) { retry: for (int c = ctl.get();;) { // Check if queue empty only if necessary. if (runStateAtLeast(c, SHUTDOWN) && (runStateAtLeast(c, STOP) || firstTask != null || workQueue.isEmpty())) return false; for (;;) { if (workerCountOf(c) >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK)) return false; if (compareAndIncrementWorkerCount(c)) break retry; c = ctl.get(); // Re-read ctl if (runStateAtLeast(c, SHUTDOWN)) continue retry; // else CAS failed due to workerCount change; retry inner loop } } boolean workerStarted = false; boolean workerAdded = false; Worker w = null; try { w = new Worker(firstTask); final Thread t = w.thread; if (t != null) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // Recheck while holding lock. // Back out on ThreadFactory failure or if // shut down before lock acquired. int c = ctl.get(); if (isRunning(c) || (runStateLessThan(c, STOP) && firstTask == null)) { if (t.getState() != Thread.State.NEW) throw new IllegalThreadStateException(); workers.add(w); workerAdded = true; int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s; } } finally { mainLock.unlock(); } if (workerAdded) { t.start(); workerStarted = true; } } } finally { if (! workerStarted) addWorkerFailed(w); } return workerStarted; }

最后

你以为是 bug? 设计线程池的大佬早就预料到了!

http://www.cnnetsun.cn/news/1740447.html

相关文章:

  • 创新方案:3步解锁VR视频自由视角,普通设备变身沉浸式探索器
  • MiniCPM-V-2_6多图像理解实战:Ollama部署+BLINK/Mantis-Eval效果验证
  • ComfyUI-KJNodes插件实战:5个高效节点让你的AI图像创作速度翻倍
  • BERT文本分割-中文-通用领域一文详解:为什么它比传统规则分段更准?
  • FramePack视频扩散技术指南:从原理解析到实战优化的完整路径
  • 开源软件的商业化和测试挑战:测试从业者的专业视角
  • 别再只调参了!从KNN到SVM,手把手教你用Python实战机器学习模型评估(附混淆矩阵与ROC代码)
  • Linux环境下的CenterPoint复现指南:从零开始的详细步骤
  • GPU与CPU差异分析
  • 如何免费解锁Cursor Pro功能:终极身份管理技术指南
  • 清音刻墨在无障碍服务落地:听障人群视频字幕自动生成实践
  • 《零基础入门Spark》学习笔记 Day 12
  • 解锁全球市场:4步掌握MoneyPrinterTurbo多语言创作技巧
  • qobuz-dl 终极指南:如何轻松下载高品质无损音乐
  • 如何挑选眼镜框
  • GHelper:突破官方软件限制的轻量级华硕硬件控制工具
  • 从单体Agent到Agent生态系统:AI应用架构的演进之路
  • 黑苹果无线网络与蓝牙驱动完全解决方案:从硬件选择到系统稳定运行
  • 从‘能通’到‘不通’:手把手用Packet Tracer复现单交换机VLAN隔离实验(含配置解析与验证)
  • 基于深度学习与大语言模型的皮肤病智能辅助诊断系统
  • 让AI替你编程:基于快马平台的多模型AI,快速生成集成第三方API的智能天气应用
  • HTML函数能否用老旧散热硅脂导致过热_导热材料老化影响【汇总】
  • 语音识别benchmark:SenseVoice-Small ONNX在AISHELL-1/THCHS-30表现
  • AI Agent Harness Engineering 的规划能力:从目标到行动的桥梁
  • Jellyfin Bangumi插件:5分钟打造完美中文番剧媒体库
  • 如何绕过百度网盘限速?这个开源工具让你免费享受会员级下载速度
  • Parasoft C++test桩函数进阶玩法:如何模拟传感器故障、控制死循环并实现用例差异化返回
  • 2026年4月怎么部署OpenClaw?本地简单流程:部署与大模型API、Skill配置教程
  • HTML转Figma:如何让网页设计与代码世界无缝对话
  • Botty深度技术解析:暗黑破坏神2重制版像素级自动化框架架构与实现