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

线程中断-interrupted方法

一、没有中断机制,代码会出什么问题?

假设 Java 没有interrupt(),你要怎么让一个正在运行的线程停下来?

方案 1:用一个volatile boolean标志位

class Worker implements Runnable { private volatile boolean running = true; public void stop() { running = false; } @Override public void run() { while (running) { // 做任务 } } }

问题在哪?

如果线程正在Thread.sleep(10000)(睡了 10 秒),你调用了stop(),把running改成false线程要睡满 10 秒才会醒来检查running。这 10 秒内它什么都干不了,也无法响应你的停止请求。

方案 2:用Thread.stop()Java 已废弃

这个方法能强制杀死线程,但问题更严重:

  • 线程可能在写文件、操作数据库、持有锁,强制杀死会导致资源泄漏、数据损坏、锁永远不释放

所以 Java 设计者面临一个矛盾:

  • 不能强制杀(太危险)

  • 不能光用标志位(线程阻塞时无法及时响应)

于是interrupt()被设计出来:它不是强制停止,而是"礼貌地通知线程:有人希望你停下来,你自己决定什么时候停"。


二、interrupt()的核心设计:协作式中断

interrupt()的设计哲学是:发通知,不强制

它只做三件事:

  1. 给目标线程设置一个"中断标志位"(true

  2. 如果目标线程正在sleep()/wait()/join()立刻唤醒它,并抛出InterruptedException

  3. 如果线程正在正常运行,它不会自动停止,需要你手动检查中断状态

为什么这样设计?因为,线程最清楚自己什么时候是"安全的停止点"。比如:

// 线程正在执行转账操作: // 1. 从 A 账户扣款 // 2. 向 B 账户加款 // 如果在这两步之间被强制中断,钱扣了但没加上,数据就不一致了。 // 所以线程自己决定:等这两步原子操作做完,再检查中断标志,安全退出。

三、代码实战:三种场景

场景 1:线程在正常运行,你调用interrupt()

public class InterruptDemo { public static void main(String[] args) throws InterruptedException { Thread worker = new Thread(() -> { // 模拟一个长时间运行的任务 for (int i = 0; i < 100000; i++) { // isInterrupted() 检查:有人让我中断吗? if (Thread.currentThread().isInterrupted()) { System.out.println("收到中断信号,我在第 " + i + " 次循环时安全退出"); return; // 自己决定在这里停 } // 做一些计算... } }); worker.start(); Thread.sleep(100); // 主线程等 100ms worker.interrupt(); // 发送中断请求 } }

输出:

收到中断信号,我在第 xxx 次循环时安全退出

关键点:

  • interrupt()只是设了个标志

  • 线程通过isInterrupted()主动检查

  • 什么时候停,由线程自己决定(这就是协作式)


场景 2:线程在sleep(),你调用interrupt()

public class SleepInterruptDemo { public static void main(String[] args) { Thread sleeper = new Thread(() -> { try { System.out.println("我要睡 10 秒..."); Thread.sleep(10000); System.out.println("睡醒了"); // 这行不会执行 } catch (InterruptedException e) { System.out.println("sleep 期间被中断了!异常信息:" + e.getMessage()); // 注意:catch 之后,中断标志位会被清空(变成 false) System.out.println("catch 后中断标志:" + Thread.currentThread().isInterrupted()); } }); sleeper.start(); // 主线程等 500ms 后中断它 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } sleeper.interrupt(); } }

输出:

我要睡 10 秒... sleep 期间被中断了!异常信息:sleep interrupted catch 后中断标志:false

设计原因:

  • 如果线程在sleep(),它无法执行isInterrupted()检查

  • 所以 JVM 设计成:收到中断时立刻抛异常,强制线程醒来

  • 但抛异常后,中断标志会被清除(这是 Java 的设计约定,防止你重复处理)


场景 3:线程在wait(),你调用interrupt()

public class WaitInterruptDemo { private static final Object lock = new Object(); public static void main(String[] args) { Thread waiter = new Thread(() -> { synchronized (lock) { try { System.out.println("我要 wait 了..."); lock.wait(); // 释放锁,进入等待 System.out.println("被 notify 了"); // 不会执行 } catch (InterruptedException e) { System.out.println("wait 期间被中断了!"); // 同样,中断标志会被清除 } } }); waiter.start(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } waiter.interrupt(); // 中断 wait 中的线程 } }

输出:

我要 wait 了... wait 期间被中断了!

sleep()的区别:

  • sleep()不释放锁,抱着锁睡觉

  • wait()会释放锁,进等待队列

  • 但两者被中断时,都会立刻InterruptedException,并清除中断标志


四、一个容易踩的坑:中断标志被清除了怎么办?

看这段代码:

while (!Thread.currentThread().isInterrupted()) { try { doWork(); Thread.sleep(1000); // 假设这里被中断 } catch (InterruptedException e) { // 异常被吞掉,什么都不做 // 糟糕!中断标志已经被清除了! } } // 因为标志被清除,循环会继续执行,线程永远停不下来!

正确做法:catch里重新设置中断标志,或者干脆退出:

while (!Thread.currentThread().isInterrupted()) { try { doWork(); Thread.sleep(1000); } catch (InterruptedException e) { // 方案 A:重新设置标志,让上层处理 Thread.currentThread().interrupt(); // 方案 B:直接 break/return,在这里处理退出 break; } }

五、总结:一张图看懂逻辑

主线程调用 t.interrupt() │ ▼ ┌─────────────────┐ │ 设置 t 的中断标志位 = true │ └─────────────────┘ │ ├──► 如果 t 正在运行 ──► t 自己用 isInterrupted() 检查 │ │ │ ▼ │ 决定什么时候安全退出 │ ├──► 如果 t 正在 sleep()/wait()/join() │ ▼ 立刻唤醒,抛 InterruptedException │ ▼ 中断标志位被自动清除(变回 false) │ ▼ 在 catch 里:要么重新 interrupt(),要么 break/return

六、核心要点(记住这几条就够了)

方法作用注意
t.interrupt()给线程 t 发中断请求只是请求,不强制
Thread.interrupted()检查当前线程是否被中断,并清除标志静态方法,会清标志
t.isInterrupted()检查线程 t 是否被中断,不清除标志实例方法
sleep/wait/join被中断立刻抛InterruptedException抛完后标志位变false

设计的本质:interrupt()提供了一种"既能唤醒阻塞线程,又不强制破坏其执行逻辑"的安全机制。没有它,你要么无法及时停止阻塞线程,要么只能用危险的强制手段。

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

相关文章:

  • 2026年想在西安找重大刑事辩护律师?哪家口碑好一文给你讲明白 - 甄选测评馆
  • lu,大鼠穿梭箱、大小鼠穿梭箱、大鼠穿梭实验箱、穿梭视频分析系统
  • Qt 死锁避坑实录:从一段“看起来很 Qt”的代码说起
  • AI 开发的下一个分水岭:从「调模型」到「调度模型」
  • IEEE期刊论文精读与完整复现 | F-WMMSE:让天线位置参与波束成形,和速率提升约20%
  • 3.Java变量与数据类型
  • 长输供热难点攻克|61.7km超长热力管线,亚控KingSCADA搭建全冗余智慧调度系统
  • 2026优质承压设备集成公司哪家好?实力靠谱承压设备集成商汇总 - 2027品牌AI展
  • 合肥巢湖市雨天窗台渗水别乱修!我的无拆窗维修全过程记录 - 趣闻早乐评
  • 国内锂电工业烤箱、注液机、转轮除湿机、NMP 回收系统靠谱厂家推荐,泽润机械为珠三角源头首选大厂 - 变量人生001
  • B样条曲线计算
  • 第6章 时域递归滤波:IIR滤波器在视频降噪中的应用
  • 2026微信小程序开发费用需要多少?哪个更具性价比?
  • 从零到一带你速通DeepSeek Harness
  • 极空间部署OneNav实战:书签分类、数据保存与公网访问
  • Easy Image X v3 26X4 深度解析:步进式装机、部署预设与无人值守直达桌面
  • 沃尔玛购物卡回收平台怎么选?看折扣与到账两个指标 - 圆圆收
  • 2026不锈钢飘带雕塑厂家选购指南及实力参考 - 曲阳嘉华园林
  • DWMBlurGlass窗口毛玻璃美化完全指南:4种材质怎么选,Win10/11标题栏一步到位的界面美化方案
  • 重庆宠物医院助理医生岗前培训 2026 想学宠物临床实操去哪里 - 湖北找学校
  • 长沙AI大模型开发培训行业评测 正规机构课程与师资配置整理 - 梦想蓝途
  • 2026年头盔安全插扣源头厂家供应商推荐:批量采购选型指南 - 汇聚至此
  • 【数据结构】二叉树的存储结构(顺序/链式)
  • 那五个永远调不对大小的窗口,终于有救了:Window Resizer 强制调整窗口大小实操指南
  • 2026年地坪漆十大品牌选型全指南:正规合规服务商盘点、多场景适配解析及签约避坑实用FAQ - 商业大观
  • 破解物理AI技术困局(37):TVA攻克多智能体协同难题
  • 多智能体应用实战 | Agent不是玩具,是生产力——OpenClaw六大企业应用场景与落地价值
  • 瓦努阿图绿卡到底靠不靠谱?这几类人办了才不亏 - 优企甄选
  • 黑苹果EFI配置从8小时缩到50分钟:OpCore-Simplify如何把复杂留给自己
  • 笔试面试一站式,考编上岸选博傲 - 博傲教育