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

孤舟笔记 并发篇二十三 线程池是如何实现线程复用的?Worker循环取任务的秘密远比你想象的精巧

文章目录一、先说结论线程复用的核心机制二、Worker线程和任务的合体三、runWorker()复用的核心循环四、getTask()从队列取下一个任务五、完整流程从提交到复用六、对比不使用线程池 vs 使用线程池线程复用机制全景回答技巧与点评标准回答加分回答面试官点评个人网站每个 Thread 只能 start 一次那线程池怎么做到复用线程的一个线程执行完任务为什么没有退出它是怎么拿到下一个任务的搞不懂线程复用的原理线程池对你来说就是黑盒。今天咱们拆开看看。一、先说结论线程复用的核心机制维度说明核心思路Worker 线程在 while 循环中反复取任务取到就执行取不到就等关键代码runWorker() 中的 while (task ! null || (task getTask()) ! null)Worker 本质继承 AQS既是线程又是任务载体首次任务Worker 创建时绑定 firstTask先执行它后续任务firstTask 执行完后从 workQueue 中取等待机制核心线程用 take() 永久阻塞非核心线程用 poll() 超时等待一句话记住线程复用就像流水线工人——干完一个零件不是下班而是伸手拿下一个没零件就等着永远不会自己走。二、Worker线程和任务的合体Worker 是 ThreadPoolExecutor 的内部类它同时继承了 AQS 并实现了 RunnableprivatefinalclassWorkerextendsAQSimplementsRunnable{finalThreadthread;// Worker 对应的线程 RunnablefirstTask;// 第一个任务可能为 null volatilelongcompletedTasks;Worker(RunnablefirstTask){setState(-1);// 禁止在 runWorker 前被中断this.firstTaskfirstTask;this.threadgetThreadFactory().newThread(this);// 用自己创建线程 }publicvoidrun(){runWorker(this);// 线程启动后执行 runWorker }}关键Worker 本身就是 Runnablethread 的 run() 方法执行的就是 Worker.run() → runWorker()。线程启动后就进入了 runWorker 的循环。三、runWorker()复用的核心循环finalvoidrunWorker(Workerw){ThreadwtThread.currentThread();Runnabletaskw.firstTask;// 先拿第一个任务 w.firstTasknull;w.unlock();// 允许被中断try{while(task!null||(taskgetTask())!null){// 核心循环w.lock();// 执行任务时加锁防止 shutdown 同时中断// 检查线程池状态if((runStateAtLeast(ctl.get(),STOP)||(Thread.interrupted()runStateAtLeast(ctl.get(),STOP)))!wt.isInterrupted())wt.interrupt();try{beforeExecute(wt,task);// 钩子方法try{task.run();// 执行任务}catch(Throwablex){afterExecute(task,x);// 钩子方法throwx;}finally{afterExecute(task,null);// 钩子方法}}finally{tasknull;// 清空下一轮从队列取 w.completedTasks;w.unlock();}}}finally{processWorkerExit(w,false);// 线程退出 }}复用的秘密全在 while 循环首次执行 Worker 绑定的 firstTask后续task getTask()从队列取取到了 → 执行 → task 置 null → 下一轮继续取取不到 → 循环退出 → 线程终止线程没有退出是因为 while 循环没结束。这就是复用的本质。四、getTask()从队列取下一个任务privateRunnablegetTask(){booleantimedOutfalse;for(;;){// ... 状态检查 ...booleantimedallowCoreThreadTimeOut||wccorePoolSize;try{Runnablertimed?workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS):// 限时等 workQueue.take();// 永久等 if(r!null)returnr;timedOuttrue;}catch(InterruptedExceptionretry){timedOutfalse;}}}场景取任务方式行为核心线程take()队列空时永久阻塞直到有任务非核心线程poll(keepAliveTime)队列空时等待 keepAliveTime超时返回 null队列有任务poll/take 立即返回拿到任务继续执行生活类比核心线程是正式员工在工位上一直等take非核心线程是临时工等了 keepAliveTime 还没事干就下班了poll 超时。五、完整流程从提交到复用提交任务 submit(task) │ ├─ workerCount corePoolSize │ └─ 是 → addWorker(task, true) → 创建 Worker绑定 firstTask │ ├─ workQueue.offer(task) │ └─ 是 → 任务入队等待空闲 Worker 来取 │ └─ 否 → addWorker(task, false) → 创建非核心 Worker Worker 生命周期 │ start() → run() → runWorker() │ while 循环 ├─ 执行 firstTask第一次 ├─ getTask() 从队列取后续 复用的关键 ├─ 取到 → task.run() ├─ 取不到 → 循环退出 → processWorkerExit() └─ 线程终止六、对比不使用线程池 vs 使用线程池// 不用线程池每个任务一个线程执行完就销毁for(inti0;i1000;i){newThread(task).start();// 创建1000个线程用完即销毁 }// 线程池10个线程循环执行1000个任务ExecutorServicepoolExecutors.newFixedThreadPool(10);for(inti0;i1000;i){pool.submit(task);// 10个Worker循环取任务复用线程 }节省了 990 个线程的创建和销毁开销。线程复用机制全景线程复用 全景 核心原理 Worker 线程在 while 循环中反复取任务 ├── firstTask → 首次执行 ├── getTask() → 后续从队列取 └── 循环退出 → 线程终止不再复用 关键方法 ├── runWorker() ── while 循环取任务并执行 ├── getTask() ── 从 workQueue 获取任务 │ ├── take() ── 核心线程永久等 │ └── poll(timeout) ── 非核心线程限时等 └── processWorkerExit() ── 线程退出善后 Worker 设计 ├── extends AQS ── 实现不可重入锁标记线程是否在执行任务 ├── implements Runnable ── 本身是可执行体 └── thread new Thread(this) ── 用自己创建线程 口诀Worker 是循环工firstTask 先干完 getTask 从队列取取到就干取不到等 核心永远等非核心限时等 while 循环不停歇线程复用自然成。回答技巧与点评标准回答线程池通过 Worker 线程的 while 循环实现线程复用。Worker 继承 AQS 并实现 Runnable创建时绑定一个 firstTask。线程启动后执行 runWorker()在 while 循环中先执行 firstTask然后不断通过 getTask() 从 workQueue 获取下一个任务。核心线程使用 take() 永久阻塞等待非核心线程使用 poll(keepAliveTime) 限时等待。只要 getTask() 能取到任务线程就不会退出从而实现复用。加分回答Worker 的 AQS 锁设计Worker 继承 AQS 实现了不可重入的互斥锁用于标记线程是否正在执行任务。shutdown() 时只中断空闲线程锁未被占用不中断正在执行任务的线程。不可重入是为了防止任务代码中调用 shutdown() 时误判线程状态beforeExecute/afterExecute 钩子runWorker() 在任务执行前后留了钩子方法子类可以覆盖来实现监控、统计、日志等功能。这是模板方法模式的体现线程复用 vs 对象池线程池的复用不是对象池那种借还模式而是循环取任务模式。线程始终持有运行权只是在不同任务之间切换。这种设计更高效避免了线程的频繁创建和上下文切换面试官点评这道题考的是你对线程池内部运作机制的深入理解。能说出while 循环取任务是核心但能讲清 Worker 的设计AQS 锁、firstTask、getTask 的区别、核心线程和非核心线程的不同等待策略、以及 beforeExecute/afterExecute 钩子的作用才说明你真的读过源码。面试官最想听到的核心认知是线程复用的本质不是线程被回收再分配而是线程一直在循环中跑只是执行的任务在变。原文阅读内容有帮助点赞、收藏、关注三连评论区等你

相关文章:

孤舟笔记 并发篇二十三 线程池是如何实现线程复用的?Worker循环取任务的秘密远比你想象的精巧

文章目录一、先说结论:线程复用的核心机制二、Worker:线程和任务的"合体"三、runWorker():复用的核心循环四、getTask():从队列取下一个任务五、完整流程:从提交到复用六、对比:不使用线程池 vs …...

别再瞎调颜色了!手把手教你用Python+OpenCV搞定ISP中的CCM矩阵(附代码)

从传感器到人眼:Python实战CCM矩阵计算与图像色彩校正 色彩校正矩阵(CCM)是图像信号处理(ISP)流水线中至关重要的环节。想象一下,当你用不同品牌的手机拍摄同一片蓝天时,为什么有些照片偏紫&…...

5分钟解锁:LinkSwift网盘直链解析的终极效率秘籍

5分钟解锁:LinkSwift网盘直链解析的终极效率秘籍 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 …...

Claude Code 接入 DeepSeek-V4-Pro

如果我们想使用 claude 的agent框架,但是受制于A社的管控,可以使用此方法。理论上可以在claude 的agent框架中使用任何模型。 1. 下载clauld code curl -fsSL https://claude.ai/install.cmd -o install.cmd && install.cmd && del in…...

如何快速打造智能机器狗:openDogV2开源四足机器人完整指南

如何快速打造智能机器狗:openDogV2开源四足机器人完整指南 【免费下载链接】openDogV2 项目地址: https://gitcode.com/gh_mirrors/op/openDogV2 想要亲手制作一只能够自主行走、感知环境的智能机械伙伴吗?openDogV2开源四足机器人项目为你提供了…...

Obsidian Excel插件:构建企业级知识库结构化数据管理的完整方案

Obsidian Excel插件:构建企业级知识库结构化数据管理的完整方案 【免费下载链接】obsidian-excel 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-excel 在知识管理领域,Obsidian以其强大的双向链接和本地优先理念赢得了技术爱好者的青睐…...

世界模型EP01:DreamZeroDreamDojo 世界模型与机器人智能的新范式

发布时间:2026年3月18日 06:30 世界模型这个概念,从2024年偶尔听到,到如今已经非常热门。延续之前的三个系列科普,Robot Data EP10 Robot Data第一季访谈总结,和Human Data 总结篇:Human Data—The “Key” to Robot Data,以及Robot Foundation model系列,2026年上半年…...

多模态检索增强技术在图像生成中的应用与优化

1. 技术背景与核心价值 在视觉内容创作领域,如何实现精准可控的图像生成一直是行业痛点。传统文本到图像(Text-to-Image)模型虽然能够根据文字描述生成图像,但在处理复杂场景时常常出现细节偏差、语义误解等问题。多模态检索增强技…...

LLM PDF Translator:基于版面分析与大模型的文档翻译工具部署与实战

1. 项目概述与核心价值 最近在折腾一个挺有意思的项目,叫 LLM PDF Translator。简单来说,它就是一个能帮你把整本PDF文档,从一种语言翻译成另一种语言,并且 最大程度保留原始排版格式 的工具。这玩意儿解决了一个很实际的痛点&a…...

机器人控制中心开发指南:Electron串口通信与数据可视化实践

1. 项目概述:一个桌面端的机器人控制中心最近在机器人开发社区里,一个名为hicoldcat/openclaw-control-center-desktop的项目引起了我的注意。乍一看这个名字,你可能会觉得它只是一个普通的桌面应用,但当你深入进去,会…...

如何让老旧电视复活:Android原生电视直播应用完整指南

如何让老旧电视复活:Android原生电视直播应用完整指南 【免费下载链接】mytv-android 使用Android原生开发的视频播放软件 项目地址: https://gitcode.com/gh_mirrors/my/mytv-android 还在为家中老旧Android电视无法流畅观看直播而烦恼吗?面对那…...

Web3资产组合SDK实战:从多链聚合到DApp开发全解析

1. 项目概述:一次关于“包”的SDK黑客松实战 最近在GitHub上看到一个挺有意思的项目,叫“Bags-SDK-hackathon”。光看标题,可能有点摸不着头脑,这“Bags”和“SDK”是怎么扯上关系的?是做一个装东西的包的SDK吗&#x…...

体验 Taotoken 官方价折扣活动对个人开发者月度账单的切实影响

体验 Taotoken 官方价折扣活动对个人开发者月度账单的切实影响 1. 个人开发者的典型模型调用场景 个人开发者或小型项目在日常开发中,通常会涉及以下几种模型调用场景:代码补全、文档生成、简单问答系统原型开发等。这些场景下,开发者往往需…...

基于Nostr协议的私信机器人框架:构建去中心化社交自动化服务

1. 项目概述:一个去中心化社交的自动化信使最近在捣鼓Nostr协议,想实现一些自动化交互,比如自动回复、关键词监控或者简单的机器人服务。在GitHub上翻找时,遇到了一个挺有意思的项目:dhalsim/nostr-dm-agent。光看名字…...

Magentic:用Python装饰器实现LLM结构化输出与函数调用

1. 项目概述:Magentic,让LLM成为你的Python函数 如果你正在用Python构建AI应用,大概率绕不开一个核心问题:如何优雅、可靠地将大语言模型(LLM)的“非结构化”文本输出,转换成你代码里可以直接使…...

游戏开发者的图像格式困境?Tacent View一站式解决所有专业纹理处理需求

游戏开发者的图像格式困境?Tacent View一站式解决所有专业纹理处理需求 【免费下载链接】tacentview An image and texture viewer for tga, png, apng, exr, dds, pvr, ktx, ktx2, astc, pkm, qoi, gif, hdr, jpg, tif, ico, webp, and bmp files. Uses Dear ImGui…...

BL602 RISC-V微控制器逆向工程与WiFi协议栈分析

1. BL602 RISC-V微控制器逆向工程实战去年拿到Pinecone开发板时,我就被BL602这颗RISC-V架构的WiFiBLE双模芯片吸引了。作为ESP32的竞品,它最大的特点就是采用了完全开源的RISC-V指令集,但配套SDK却充满了闭源二进制文件。这让我想起了早些年逆…...

Reloaded-II 下载卡顿终极解决方案:3个技巧让你的Mod安装快如闪电 [特殊字符]

Reloaded-II 下载卡顿终极解决方案:3个技巧让你的Mod安装快如闪电 🚀 【免费下载链接】Reloaded-II Universal .NET Core Powered Modding Framework for any Native Game X86, X64. 项目地址: https://gitcode.com/gh_mirrors/re/Reloaded-II Re…...

2026届毕业生推荐的六大AI论文工具实测分析

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 顺着学术写作需求一天天增长的趋势,AI论文工具变成了研究者提高效率的关键辅助办…...

从PACS抓取的DICOM文件在SimpleITK中shape突变?深度拆解Transfer Syntax隐式VR转换陷阱

更多请点击: https://intelliparadigm.com 第一章:从PACS抓取的DICOM文件在SimpleITK中shape突变?深度拆解Transfer Syntax隐式VR转换陷阱 DICOM Transfer Syntax 与像素数据布局的隐式耦合 当从PACS系统(如Orthanc或DCM4CHEE&a…...

别再让Maven打包的jar包名又长又乱了!finalName标签的3种实战用法(含变量技巧)

优雅定制Maven构建产物:finalName标签的深度实践指南 每次在服务器上部署Java应用时,看到那些带着冗长版本号的jar包名称,你是否感到一丝烦躁?当运维同事抱怨"这个jar包名太复杂,脚本里写起来麻烦"时&#x…...

揭秘OLAP数据库预计算技术

揭秘OLAP数据库预计算技术OLAP数据库通常通过预计算技术将复杂查询的响应时间从分钟级压缩至毫秒级,其核心逻辑在于‌以空间换时间‌:提前计算并存储聚合结果(如SUM、AVG),避免实时扫描原始数据并进行计算。增量物化视…...

基于Axon.MCP.Server构建AI Agent工具:.NET 8实现MCP协议实战

1. 项目概述与核心价值最近在折腾AI Agent开发,特别是想给Claude Desktop或者Cursor这类工具加上自定义的“工具箱”,让它们能直接操作我的本地数据库、调用内部API,或者读取特定格式的日志文件。市面上通用的MCP(Model Context P…...

别再为MIR7和MIRO搞混了!详解SAP发票校验的差异与实战增强配置

SAP发票校验实战指南:MIRO与MIR7的核心差异与增强配置解析 每次月末对账时,财务部门的张经理总会遇到一个奇怪现象——明明上个月已经处理过的采购订单,在MIR7事务码中又出现了待开票数据。而使用MIRO录入日常发票时,系统却能准确…...

WarcraftHelper完全指南:5分钟让经典魔兽在现代电脑上重获新生

WarcraftHelper完全指南:5分钟让经典魔兽在现代电脑上重获新生 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为《魔兽争霸3》在Wind…...

抖音无水印视频下载终极指南:3分钟实现高清视频保存

抖音无水印视频下载终极指南:3分钟实现高清视频保存 【免费下载链接】douyin_downloader 抖音短视频无水印下载 win编译版本下载:https://www.lanzous.com/i9za5od 项目地址: https://gitcode.com/gh_mirrors/dou/douyin_downloader 你是否曾经想…...

小红书无水印下载神器:从入门到精通的完整指南

小红书无水印下载神器:从入门到精通的完整指南 【免费下载链接】XHS-Downloader 小红书(XiaoHongShu、RedNote)链接提取/作品采集工具:提取账号发布、收藏、点赞、专辑作品链接;提取搜索结果作品、用户链接&#xff1b…...

多模态大模型优化与量化部署实战

1. 项目背景与核心价值 在当下AI技术快速迭代的浪潮中,大型语言模型(LLM)正从单一文本处理向多模态融合方向演进。OmniVinci项目正是针对这一趋势提出的创新解决方案,它通过架构优化与量化部署技术,显著提升了多模态大…...

告别TabControl!用Prism区域管理重构你的WPF导航,模块化开发真香了

重构WPF导航架构:Prism区域管理的模块化实践指南 当你的WPF应用从简单的工具演变为复杂系统时,传统的导航实现方式往往会成为技术债务的重灾区。那些曾经看似高效的TabControl和ContentControl绑定,如今却让代码库变得臃肿不堪。每次新增功能…...

终极指南:如何用VideoDownloadHelper快速下载网页视频的完整教程

终极指南:如何用VideoDownloadHelper快速下载网页视频的完整教程 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 还在为无法保存网…...