如何停止一个线程?

1. 不要用的方法

1.1 Thread.stop()

  • 早已废弃@Deprecated),会直接释放线程持有的所有锁。
  • 可能导致对象处于不一致状态(例如正在写一个共享变量,被 stop 中断,数据可能损坏)。
  • 可能引发死锁或数据不一致。

1.2 Thread.suspend() / Thread.resume()

  • 同样已废弃,容易在持锁时挂起线程,导致永久死锁

2. 推荐的线程停止方式

Java 规范倡导所谓 "协作式中断" (Cooperative Interruption):

→ 不强制杀死线程,而是给线程一个信号,让它自己停下来

核心思路:

  1. 外部线程设置某种"停止标记"或调用 interrupt()
  2. 线程内部定期检查标记,当检测到需要停止时,自己安全退出。

2.1 方法一:使用标志位

java 复制代码
public class StopThreadDemo implements Runnable { 
    private volatile boolean stopRequested = false; 
    public void stop() { stopRequested = true; } 
    @Override public void run() { 
        while (!stopRequested) { // 线程工作 System.out.println("线程运行中..."); 
            try { Thread.sleep(500); } 
            catch (InterruptedException e) { // 如果需要响应中断,可在这里 break 
                Thread.currentThread().interrupt(); // 保留中断状态 } } 
       System.out.println("线程安全停止"); } 
public static void main(String[] args) throws InterruptedException { 
    StopThreadDemo task = new StopThreadDemo(); 
    Thread t = new Thread(task); 
    t.start(); 
    Thread.sleep(2000); 
    task.stop(); // 通知线程停止 } }

要点:

  • volatile 确保多线程可见性,避免被编译器优化成缓存变量。
  • 线程内部必须自己在循环条件中检查 stopRequested

2.2 方法二:使用 interrupt() + 检查中断状态

当线程处于阻塞状态(sleep()wait()join())时,调用 interrupt() 会抛 InterruptedException

java 复制代码
public class InterruptDemo implements Runnable { 
    @Override public void run() { 
        while (!Thread.currentThread().isInterrupted()) { 
            System.out.println("线程运行中..."); 
            try { 
                Thread.sleep(500); } 
            catch (InterruptedException e) { 
                System.out.println("线程被中断,准备停止..."); 
                Thread.currentThread().interrupt(); // 重新设置中断状态(因为异常会清除中断标记) 
                break; } } 
            System.out.println("线程安全退出"); } 
public static void main(String[] args) throws InterruptedException { 
    Thread t = new Thread(new InterruptDemo()); 
    t.start(); Thread.sleep(2000); 
    t.interrupt(); // 通知线程停止(协作式) } }

要点:

  • interrupt() 并不会强制杀死线程,而是给线程一个 中断标记
  • 对阻塞方法,interrupt() 会让它抛 InterruptedException
  • 线程必须捕获并自己退出(或在循环判断中断标记时退出)。

2.3 方法三:结合 ExecutorService 提交任务

使用 线程池 API,可以优雅地停止线程:

java 复制代码
ExecutorService executor = Executors.newSingleThreadExecutor(); 
Future<?> future = executor.submit(() -> { 
    try { 
        while (!Thread.currentThread().isInterrupted()) { // 工作代码   
                Thread.sleep(500); } } 
    catch (InterruptedException e) { 
        Thread.currentThread().interrupt(); 
     } }); 
        Thread.sleep(2000); 
        future.cancel(true); // true 表示试图中断线程 executor.shutdown();
  • future.cancel(true) 相当于调用底层线程的 interrupt()

3. 底层原理

  • 每个线程对象里有一个 中断标志位interrupted)。
  • interrupt() 只是把标志位置为 true,对阻塞方法则会抛 InterruptedException
  • Thread.interrupted()静态方法,返回当前线程的中断状态,并清除标志位。
  • isInterrupted()实例方法,查询线程的中断状态,不会清除标志。
相关推荐
咖啡啡不加糖30 分钟前
Grafana 监控服务指标使用指南:打造可视化监控体系
java·后端·grafana
gAlAxy...42 分钟前
SpringBoot Servlet 容器全解析:嵌入式配置与外置容器部署
spring boot·后端·servlet
BYSJMG1 小时前
计算机毕业设计选题推荐:基于Hadoop的城市交通数据可视化系统
大数据·vue.js·hadoop·分布式·后端·信息可视化·课程设计
BYSJMG1 小时前
Python毕业设计选题推荐:基于大数据的美食数据分析与可视化系统实战
大数据·vue.js·后端·python·数据分析·课程设计·美食
东东5162 小时前
OA自动化居家办公管理系统 ssm+vue
java·前端·vue.js·后端·毕业设计·毕设
程序员鱼皮2 小时前
前特斯拉 AI 总监:AI 编程最大的谎言,是 “提效”
前端·后端·ai·程序员·开发
好好研究3 小时前
SpringBoot使用外置Tomcat
spring boot·后端·tomcat
索荣荣3 小时前
Spring Boot 实现DOCX转PDF(基于docx4j的轻量级开源方案)
spring boot·后端·pdf
mit6.8243 小时前
[todo]10个常见的后端框架
后端
没有bug.的程序员3 小时前
Spring Boot 与 Sleuth:分布式链路追踪的集成、原理与线上故障排查实战
java·spring boot·分布式·后端·分布式链路追踪·sleuth·线上故障排查