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

工作 8 年才弄明白,原来,这才是JDK推荐的线程关闭方式

JDK在线程的Stop方法时明确不得强行销毁一个线程要优雅的退出线程。何谓优雅退出线程即业务将进行中请求正确被处理取消待执行请求执行资源回收最终Thread Runable run 方法return 结束执行。首先问为什么要退出一个线程再提问如何退出一个线程需要线程退出的常见场景任务执行完成或异常终止任务认为无需再占用线程。线程池根据当前任务执行情况伸缩线程池。当任务执行较少时退出空闲的线程。服务或进程在关闭阶段例如滚动发布时需要退出线程、关闭线程池、关闭进程。定时任务、周期任务需要终止执行时需要退出当前线程。或者退出当前任务的执行。总之既然能创建一个线程就会有退出一个线程的能力。也会有退出线程的场景。关闭一个线程的方式分为两种类型:通知线程主动关闭和强行关闭销毁线程。优雅关闭Or强行关闭标题好处坏处优雅关闭主动通知线程关闭能优雅退出线程保证资源被释放保证处理中请求正确被处理完成无法立即关闭线程执行中的任务不响应关闭信号拒绝关闭线程强行关闭线程可以立刻关闭线程存在资源未释放、处理中请求异常中断例如分布式锁漏释放。写流程异常中断数据不一致重试也无法恢复实际上强行关闭一个线程坏处很多假如要释放分布式锁前突然关闭线程那么这个分布式锁就无法释放。导致后续正常请求加锁失败被阻塞影响用户提单等。强行关闭一个线程无异于给服务器直接断电。其他语言和Java语言退出线程的方式除了Java其他语言如何退出线程呢实际上每一种实现方式都有。例如C中可以通过ExitThread、TerminateThread强行终止线程执行。linux既提供了pthread_exit C语言系统调用强行关闭线程也提供了pthread_cancel通知线程关闭等优雅退出方式。Java 也分别提供优雅和强制两种退出方式但是目前jdk中明确极不推荐强制中断线程在Thread.stop()强制中断线程的注释中 JDK这样解释Thread.stop() 这种方法本身就是不安全的Stop一个线程会随之解锁这个线程所持有的监视器可以理解为锁如果受这些监视器锁保护的临界对象处在不一致状态则其他线程可能会看到这些对象处于不一致状态那么将导致未知的行为。对Thread.Stop()的调用应该被简单的代码代替例如 修改一个变量目标线程定期检查这个变量有序从run 方法return出来。如果目标线程在一个条件变量上wait则其他线程应该使用interrupt方法中断目标线程。实际上关闭一个线程强行和通知是两种理念即是否应该相信线程任务的开发者优雅的、快速的主动退出线程而不是被其他线程强制终止。 在Java中退出线程的方式只有一种推荐即优雅退出并且jdk也给了建议通过修改变量由目标线程定期检查状态。或者通过interrupt中断方式通知目标线程。下面我们探讨下如何优雅退出一个线程优雅退出线程有哪些方式呢业务字段标记业务系统经常遇到终止一个任务的诉求例如系统中存在定时任务例如外卖券包在过期后未使用的金额自动给用户退款。假设任务执行中我需要重新制定任务的入参需要先终止任务。如何做呢大部分任务类代码都会循环处理例如扫描全表执行某个业务逻辑。一定存在循环处理的场景可以在循环入口处判断任务是否需要终止执行这样通过控制这个字段我们就可以终止任务执行。具体实施时可以通过配置中心控制某一个任务是否要终止。while(config.isTaskEnable()){//从配置中心获取任务是否要终止 //循环执行业务逻辑。直到执行完成退出或者被终止。 }这种退出方式是告知线程“你应该在合适时机退出” 由线程自己选择在合适的时机检查该状态。那么开发者在设计任务代码时就要提前设计 合理的退出点在退出点检查是否需要退出。Thread.interrupt()JDK中提到了如果目标线程没有处于运行态而是处于阻塞状态自然无法检查退出的状态标记如何通知这个线程退出呢JDK: 如果目标线程在一个条件变量上wait则其他线程应该使用interrupt方法中断目标线程。interrupt的JDK注释提到如果其他线程调用目标线程的interrupt方法恰好目标线程在调用. Object.wait()object.join(Object.sleep()等方法时目标线程的中断位标记被清除同时目标线程会立即从sleep、wait等调用中恢复并且被抛出InterruptException。如果目标线程在IO操作中被阻塞例如io.channels.InterruptibleChannelChannel将被关闭线程的中断位被设置同时目标线程收到java.nio.channels.ClosedByInterruptException。如果目标线程被阻塞在java.nio.channels.Selector线程中断状态被设置然后目标线程立即从select中返回非零值。如果其他条件都不成立该线程中断位会被设置。线程中断位标记了当前线程是否处于被中断状态并且提供了Thread.isInterrupted方法查看当前是否处于中断位那为什么目标线程阻塞在Object.wait()Sleep()方法时抛出了interruptException会取消标记呢实际上interrupt操作执行两件事1设置中断位标记 2通过unpark唤醒目标线程。park和unpark分别可以阻塞线程和唤醒线程推荐一个非常好的博客 通过JVM源码分析 interrupt和sleep的实现原理。# jvm源码分析之interrupt()然而目标线程醒来时会检查当前是否处于中断位如果是sleep或者wait操作。如果处于中断位则取消中断位抛出异常。取消中段位的原因应该是一种规范即抛出中断异常即通知了线程中断无需再用中段位标记。其他场景2、场景3 在被唤醒后分别执行对应的中断响应策略。interrupt中断逻辑是确定的业务线程要考虑自己是否调用了sleep、wait或者io、selector等操作根据不同的场景选择自己合适的中断响应策略。那么推荐业务线程如何响应中断呢推荐的中断响应策略立即响应中断目标线程的任务在InterruptedException异常处理中要主动回收资源打印日志退出任务执行。目标线程如果没有阻塞操作例如sleep、wait。可以通过 Thread.isInterrupted()查看当前中断位状态如果被中断了则采取以上第一步操作。忽略中断交给上一层处理所谓上一层可以理解为是调用堆栈的上一层例如本层代码不负责处理中断这个场景那么Interrupt异常被抛出后可以选择如何方案抛出InterruptedException给上层由上层代码处理。调用Thread.interrupt()。重新设置中断位标记(自己中断自己)。由上游代码在本层方法返回后检查中断位标记进行中断处理。当然最推荐的方式还是抛出InterruptedException让上游感知到下游调用链中存在阻塞让上游对中断异常进行处理。千万不要吞掉中断什么是吞掉中断例如当sleep抛出InterruptedException后忽略异常不执行任何操作继续执行业务逻辑。for (int i 0; i cnt; i) { try { //执行业务逻辑 Thread.sleep(10000); } catch (InterruptedException e) { System.out.println(被中断); } System.out.println(子线程执行中); }如果这样处理中断异常被忽略中断标记位也被忽略。即便上游方法对中断有处理策略也无法感知到中断。例如上游调用可能会判断while(true){ callChildMethod();//调用下游方法但是下游吞掉了中断 if (Thread.currentThread().isInterrupted()) { //回收资源退出线程 } }有人会问既然上层都能知道处理中断为什么下层方法开发者会不记得抛出中断或重置中断位呢因为上下两层很可能不是一个开发者。例如上层是通用的框架代码定义了任务的指定逻辑提供了扩展点方法下游只需要实现扩展方法即可。但是另一个开发者在实现扩展点方法时吞掉了中断异常导致本来框架层已经处理好中断了但还是无法响应中断。所以中断的响应是需要上下层每一层代码逻辑都需要考虑的事情。就算框架层处理好中断异常处理业务逻辑层也要关注中断处理。最后提醒一下Thread.interrupted方法会返回当前中断标记并且取消中断位。如果只查询中断位不想清理可以使用 Thread.isInterrupted()。总结不推荐强制销毁线程会导致资源无法被释放进行中请求无法正常处理完导致业务数据处于不可知的状态。Java推荐优雅退出线程。业务层可以使用字段标记定期检查是否需要退出任务。Thread.interrupt中断目标线程、isInterrupted查询中断位标记。使用Thread.interrupt处理中断也可以优雅退出但需要上下层堆栈都要关注中断不得吞掉中断。最后分享下五阳的浏览器AI插件没想到火了累计下载 1000同时提问豆包 DeepSeek GPT Gemini等10大 AI 平台还支持查询必应 百度 谷歌三大搜索引擎极大提升资料检索和学习效率领取链接

相关文章:

工作 8 年才弄明白,原来,这才是JDK推荐的线程关闭方式

JDK在线程的Stop方法时明确不得强行销毁一个线程,要优雅的退出线程。 何谓优雅退出线程,即业务将进行中请求正确被处理,取消待执行请求,执行资源回收,最终Thread Runable run 方法return 结束执行。 首先问为什么要退…...

OpenClaw调试技巧:千问3.5-9B任务失败日志分析方法

OpenClaw调试技巧:千问3.5-9B任务失败日志分析方法 1. 为什么需要关注OpenClaw任务日志 上周我在尝试用OpenClaw自动整理技术文档时,遇到了一个诡异现象:任务明明显示"执行成功",但最终输出的Markdown文件却缺失了关键…...

被封杀三天后,龙虾带着“复仇版本“杀回来了

OpenClaw 4.5版本上线,能直接生成视频、图片和音乐。 有些故事,编剧都不敢这么写。 几天前,Anthropic对OpenClaw下了"封杀令"——只要系统提示词中出现OpenClaw的字样,Claude就会直接拒绝请求,返回一个冷冰…...

用GitHub Copilot 10分钟开发真寻Bot插件:以DeepSeek对话功能为例(附完整猫娘角色Prompt)

10分钟用GitHub Copilot打造真寻Bot猫娘对话插件:从零到部署的完整指南 引言:当AI助手遇上二次元聊天机器人 在QQ群聊中,你是否遇到过那些能对答如流的智能机器人?它们不仅能回答各种问题,还能扮演特定角色与用户互动。…...

华为元老许映童下周敲钟:思格新能开启招股:估值超100亿美元 高瓴是基石

雷递网 雷建平 4月8日思格新能源(上海)股份有限公司(简称:“思格新能”,股票代码:“06656”)今日开启招股,准备2026年4月16日在港交所上市。思格新能计划发售1357.39万股&#xff0c…...

nCode后处理实战:5个云图显示问题及快速解决方法(附截图)

nCode后处理实战:5个云图显示问题及快速解决方法(附截图) 刚接触nCode的工程师常常会在后处理阶段遇到各种云图显示问题——全红/全蓝的单调色块、突然出现的NaN警告、无限寿命区域干扰有效数据观察……这些看似简单的可视化问题,…...

从零到一:借助MCP与Neo4j实现无代码知识图谱的快速落地

1. 为什么你需要无代码知识图谱 想象一下这样的场景:你手头堆积着大量会议记录、产品文档和客户反馈,这些信息就像散落的拼图碎片,彼此之间似乎存在某种联系,但你却找不到合适的方法把它们串联起来。传统的数据处理工具面对这种非…...

Nextjs从入门到实战保姆级教程:环境配置与项目初始化

本系列文章将围绕Next.js技术栈,旨在为AI Agent开发者提供一套完整的客户端侧工程实践指南。 本章将引导你完成 Next.js 开发环境的搭建,创建第一个项目并理解其基本结构。我们将详细说明每个步骤的原理,确保你不仅知道"怎么做"&am…...

5. 你是怎么理解ES6中 Promise的?使用场景?

一、先给面试官一个结论版如果面试官问 "你怎么理解 Promise?" ,不要上来就背 API。 更好的开场是先说本质:Promise 是 ES6 引入的一种用于处理异步操作的解决方案。 它的核心价值是:把异步操作的最终结果(成…...

为机械臂视觉抓取铺路:在ROS Melodic环境下,一步步配置YOLOv5的Python和PyTorch依赖

为机械臂视觉抓取铺路:在ROS Melodic环境下配置YOLOv5的Python和PyTorch依赖 机械臂视觉抓取是当前工业自动化和机器人研究的热点领域,而YOLOv5作为目标检测的利器,能够为机械臂提供精准的物体定位信息。但在实际部署中,开发者常…...

【Keil实战】巧用Debug功能优化程序运行时间精度

1. 为什么需要精确测量程序运行时间 在嵌入式开发中,程序运行时间的精确控制往往直接关系到系统性能。就拿电机控制来说,PWM信号的更新频率如果不够精确,轻则导致电机抖动,重则可能烧毁驱动电路。我去年做过一个四轴飞行器的项目&…...

软考机考绘图技巧与实战指南

1. 软考机考绘图工具基础操作 第一次参加软考机考的朋友们,最头疼的莫过于绘图题了。我当年第一次考试时,看到屏幕上密密麻麻的绘图工具,手指在键盘上悬了半天都不知道该点哪个按钮。后来经过多次实战,总结出一套快速上手的方法。…...

Zig新手必看:如何用zigcli快速构建命令行工具(附完整代码示例)

Zig语言实战:从零构建命令行工具的完整指南 引言:为什么选择Zig开发命令行工具? 在当今编程语言百花齐放的时代,Zig以其独特的魅力吸引着系统级开发者的目光。这门新兴语言融合了C语言的底层控制能力与现代语言的开发体验&#xf…...

3D Hough变换在自动驾驶点云平面检测中的优化实践

1. 3D Hough变换在自动驾驶中的核心价值 当激光雷达扫描周围环境时,会产生数百万个三维空间中的离散点,这就是我们常说的点云数据。想象一下,你站在城市街头,眼前所有物体都被转化为密密麻麻的彩色点,就像星空中的繁星…...

三极管基极电阻设计与工程实践

1. 三极管基极电阻的必要性解析在电子电路设计中,三极管作为最基础的半导体器件之一,其基极电阻的配置往往被初学者忽视。实际上,这两个电阻(限流电阻和上拉/下拉电阻)的设计直接影响着电路的可靠性和稳定性。以常见的…...

Cursor 3 来袭:编程已不是敲键盘,而是指挥智能体!

2026 年 4 月,AI 编程工具巨头 Cursor 正式发布新一代产品 Cursor 3。与传统的代码编辑器不同,Cursor 3 将开发者的交互界面从“键盘敲击”转向了“智能体指挥”。它不再把 VS Code 视为核心工作台,而是将其降级为一种“备选方案”。该工具的…...

武汉围挡厂家:装配式市政围挡选购指南

随着城市基建与市政施工持续推进,施工围挡已不再是单一的隔离设施,而是集安全防护、规范施工、城市风貌管理于一体的工程配套产品。对于武汉及华中地区工程相关从业者而言,科学选择适配项目需求的装配式围挡,对施工安全、验收合规…...

OpenCV踩坑记:为什么cv2.imread读‘坏图’不返回None?深度解析JPEG文件结构与解码陷阱

OpenCV图像读取陷阱:JPEG文件损坏时cv2.imread为何不返回None? 在计算机视觉项目开发中,处理JPEG图像时经常会遇到这样的场景:明明系统提示"Premature end of JPEG file"警告,但cv2.imread()却依然返回了一个…...

Qwen3.5-9B高效编码:OpenClaw自动补全Python函数

Qwen3.5-9B高效编码:OpenClaw自动补全Python函数 1. 为什么需要AI代码补全? 作为一个长期与Python打交道的开发者,我经常陷入这样的困境:在深夜赶项目时,明明知道要实现什么功能,却卡在具体函数实现的细节…...

OpenClaw技能开发入门:为Qwen2.5-VL-7B定制图文处理模块

OpenClaw技能开发入门:为Qwen2.5-VL-7B定制图文处理模块 1. 为什么需要定制技能? 去年夏天,我遇到一个头疼的问题:每天需要处理大量产品截图和说明文档的匹配工作。手动核对图片与文字描述是否一致,不仅耗时还容易出…...

告别命令行恐惧!用Docker Desktop可视化界面5分钟搞定Ollama部署(附端口映射避坑指南)

告别命令行恐惧!用Docker Desktop可视化界面5分钟搞定Ollama部署(附端口映射避坑指南) 如果你对命令行操作感到头疼,却又想快速体验Ollama的强大功能,这篇文章正是为你准备的。我们将完全避开复杂的终端指令&#xff…...

LangChain4j的ChatMemoryProvider实战:如何为不同用户/线程创建独立的AI对话记忆?

LangChain4j多用户对话隔离实战:ChatMemoryProvider架构设计与生产级优化 想象一下这样的场景:你的电商客服机器人正在同时处理数百个用户的咨询,每个用户都在进行独立的对话。突然,用户A询问订单状态,机器人却回复了用…...

OpenClaw夜间值守:Qwen3.5-9B监控服务器报警截图

OpenClaw夜间值守:Qwen3.5-9B监控服务器报警截图 1. 为什么需要AI值守夜间监控? 凌晨3点的服务器报警短信,可能是运维工程师最不愿看到的通知之一。传统监控系统虽然能发出警报,但往往存在两个痛点:一是误报率高&…...

基于STM32的智能录音机设计与实现

1. 项目概述这个基于STM32的录音机项目是我最近完成的一个嵌入式系统设计实践。作为一个经常需要记录会议和灵感的人,我一直对市面上的录音设备不太满意——要么功能单一,要么价格昂贵。于是决定自己动手,用STM32F103C8T6作为主控&#xff0c…...

Limine混合ISO制作教程:BIOS/UEFI双启动镜像的完整流程

Limine混合ISO制作教程:BIOS/UEFI双启动镜像的完整流程 【免费下载链接】limine Modern, advanced, portable, multiprotocol bootloader and boot manager. 项目地址: https://gitcode.com/gh_mirrors/li/limine Limine是一款现代化、先进的可移植多协议引导…...

详细解析Spring如何解决循环依赖问题居

AI训练存储选型的演进路线 第一阶段:单机直连时代 早期的深度学习数据集较小,模型训练通常在单台服务器或单张GPU卡上完成。此时直接将数据存储在训练机器的本地NVMe SSD/HDD上。 其优势在于IO延迟最低,吞吐量极高,也就是“数据离…...

大卫小东(Sheldon)氯

Issue 概述 先来看看提交这个 Issue 的作者是为什么想到这个点子的,以及他初步的核心设计概念。?? 本 PR 实现了 Apache Gravitino 与 SeaTunnel 的集成,将其作为非关系型连接器的外部元数据服务。通过 Gravitino 的 REST API 自动获取表结构和元数据&…...

学术PDF处理术:OpenClaw+Qwen3-32B实现论文关键图表提取

学术PDF处理术:OpenClawQwen3-32B实现论文关键图表提取 1. 为什么需要自动化PDF图表提取 作为一名经常需要阅读大量学术论文的研究者,我长期被一个问题困扰:如何高效地从PDF论文中提取关键图表和数据。传统方法要么依赖手动截图和转录&…...

【MinerU】Docker构建实战:从零到一打造内网可用的PDF解析镜像

1. 为什么需要内网可用的PDF解析镜像 最近在帮客户部署一个PDF解析系统时,遇到了一个典型的企业级需求:在内网环境中运行MinerU这个强大的PDF解析工具。你可能要问,为什么不能直接用官方镜像?这里有几个现实问题: 首…...

Linux下Chrony时间同步配置与优化实战

1. 为什么你的服务器需要Chrony时间同步? 想象一下这样的场景:你在银行转账时,交易记录显示的时间比实际时间慢了3秒;或者分布式数据库集群中,不同节点的时间差了0.5秒。这些看似微小的时间差异,轻则导致日…...