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

Java线程池中的线程是如何复用的

Worker.run() 中的 while 同一线程可持续消费任务的循环复用:首先执行初始消费任务: firstTask,再循环调用 getTask() 阻止获取任务;getTask() 返回 null(shutdown、stop 或空闲加时)循环退出,线程终止。

Worker.run() 里那个 while 循环是什么?

线程复用的关键隐藏在Worker类的run()在方法上——它在执行之前就退出了,而是继续从阻塞队列中提取任务。这个循环不是“重复启动新线程”,而是相同的Thread反复调用对象task.run()

常见错误:认为线程池 submit 一次新建一个线程;发现线程数稳定 corePoolSize,但任务仍在运行——事实上,同一行程正在循环消费。

  • Worker初始化将绑定一个初始化firstTask,只有在执行完成后才进入循环
  • 在循环体中调用getTask(),这种方法会阻止等待(例如使用)LinkedBlockingQueue.poll(timeout)
  • 如果getTask()返回null(超时,线程池 shutdown、或达到 maximumPoolSize 后空闲时间超时),循环退出,线程自然结束
  • 注意:runWorker(Worker w)是实际执行循环的入口,Worker.run()只是委托给它

getTask() 返回 null 三个典型的时机

线程复用不是无限的,getTask()返回null这意味着这个Worker退出。这不是 bug,回收机制设计良好。

容易踩的坑:手柄allowCoreThreadTimeOut = truekeepAliveTime = 0混用,导致 core 线程也立即被销毁,但没有人排队处理任务。

  • 线程池已shutdown,而且工作队列为空 → 立即返回null
  • 线程池已stop→ 无论队列是否空,直接返回null
  • 线程空闲超时:当前线程数 > corePoolSize,且从队列 poll 超过keepAliveTime未拿到任务 → 返回null

为什么 Worker 继承 AQS 却不用锁?

Worker继承AbstractQueuedSynchronizer,但没有用它作为互斥锁,而是借用了它 state 字段和 CAS 原语,实现线程中断状态的原子控制。

使用场景:调用时thread.interrupt()确保不干扰正在运行的任务(例如,任务本身也在调用)interrupt()),也不能错过中断信号。

  • WorkerAQS.setState(0)表示“允许中断”,setState(1)表示“运行中禁止中断”
  • runWorker()在执行任务之前开始调用interruptIfStarted(),只在 state == 1 真正中断线程的时间
  • 若任务本身被调用Thread.sleep()queue.take(),中断会抛出InterruptedException,此时,线程不会立即退出,而是继续下一轮循环 —— 这是重用的前提

自定义 ThreadFactory 最容易被忽视的点

许多人认为只要重写newThread()可以控制线程行为,但忘记了Worker在构造过程中对线程进行处理target设为自身(Runnable),而不是用户传递的任务。

后果:如果你在线程工厂设置了线程setUncaughtExceptionHandler,它确实有效,但如果试图通过setContextClassLoader影响任务执行环境的可能性很大——因为任务是在Worker.run()内部调用取决于上下文类加载器Worker创建线程时的快照不是你 newThread 时设的那个。

  • 务必在newThread()有意义的线程名设置在其中,如"biz-pool-worker-" + counter.getAndIncrement(),否则,堆栈里全是pool-1-thread-1
  • 不要依赖线程工厂修改线程优先级——JVM 规范不能保证跨平台的有效性,可能会被容器或安全策略拦截
  • 若需传递上下文(如 TraceId),不能依靠线程局部变量的初始化execute()submit()时显式包装任务(例如使用)new ThreadLocalContextWrapper(task)


http://www.jsqmd.com/news/506530/

相关文章:

  • 机械行业PLM系统如何通过umeditor控件实现三维模型截图上传?
  • 告别环境配置烦恼:通义千问1.8B Docker直装方案实测
  • 2026年水上乐园规划设计公司盘点,可做前期沟通的怎么选择 - myqiye
  • 2026年彩妆培训哪家好?学员口碑揭晓答案,目前靠谱的彩妆培训口碑分析精选优质品牌解析 - 品牌推荐师
  • Leather Dress Collection参数详解:各LoRA触发词、推荐权重与适用风格
  • Qwen3-ASR-0.6B企业提效案例:市场部日均200+小时播客音频自动转稿降本70%
  • OpenSpeedy完全指南:10分钟掌握免费开源游戏变速技巧
  • Python高效文件打包与压缩实战:深入掌握tarfile模块
  • 【AUTOSAR CP 4.4+以太网栈深度适配】:如何用纯C实现SOME/IP序列化/反序列化——内存占用降低42%,时延压至83μs(实测数据)
  • 永磁同步电机双环与三环控制仿真模型的构建与参考资料详解
  • ClawdBot优化升级:如何更换模型?Qwen3到GLM4切换指南
  • 暗刃出鞘:DarkSword漏洞工具席卷全球,iOS安全防线面临全新挑战
  • 永磁同步电机 PMSM 负载状态估计那些事儿
  • 国内开发者必备:3个稳定快速的NuGet镜像源配置指南(附测速对比)
  • Qwen3-ForcedAligner-0.6B保姆级教程:离线运行、JSON导出、SRT一键生成
  • 智慧化建筑物 裂缝空洞检测数据集 目标检测、裂缝、空洞、缺陷检测、建筑检测、YOLO数据集|
  • JetBrains全家桶长期免费激活与试用重置全攻略
  • VibeVoice开发者工具:RESTful API与SDK集成前景分析
  • 西门子S7-200PLC中断指令实战:从外部触发到高速计数器完整案例解析
  • EcomGPT电商大模型效果展示:输入‘夏季’自动关联‘透气/速干/防晒’等技术参数
  • CosyVoice流式传输实战:从入门到生产环境部署
  • 终极Windows Cleaner使用指南:快速解决C盘爆红问题
  • Prepar3D开发实战02:从零构建自定义飞行模型与SDK集成
  • 从Altium Designer到Cadence Allegro 17.4:一名工程师的转型实战指南
  • 增亮膜(DBEF)市场:57.7亿规模下的3.9%复合增长与技术创新浪潮
  • 视频PPT提取神器:3步将视频课件秒变清晰PDF文档 [特殊字符]→[特殊字符]
  • CLIP-GmP-ViT-L-14详细步骤:从零部署图文匹配测试工具(含Softmax置信计算)
  • MDK开发中,__packed和#pragma packed到底怎么选?一个指针错误引发的深度解析
  • 从单元测试到HIL闭环验证,车载C语言功能安全测试全流程拆解,含VectorCAST+LDRA+自研脚本三工具链协同方案
  • SolidWorks 2024实战:从零开始设计树莓派小车的摄像头支架(附B站教程)