如何停止一个线程?

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()实例方法,查询线程的中断状态,不会清除标志。
相关推荐
软件管理系统25 分钟前
SpringBoot的旧物回收商城的设计与实现
spring boot·后端
IT_陈寒33 分钟前
Redis性能提升50%的7个实战技巧,连官方文档都没讲全!
前端·人工智能·后端
Gogo81640 分钟前
clsService 全局变量(隐形背包)
后端
计算机毕设指导61 小时前
基于微信小程序+django连锁火锅智慧餐饮管理系统【源码文末联系】
java·后端·python·mysql·微信小程序·小程序·django
小鸡脚来咯1 小时前
RabbitMQ详解(从入门到实战)
开发语言·后端·ruby
古城小栈2 小时前
Spring Boot 3.3 整合 AI 工具链:自动生成接口文档
人工智能·spring boot·后端
踏浪无痕2 小时前
为什么 Spring Cloud Gateway 必须用 WebFlux?
后端·面试·架构
码匠君2 小时前
Dante Cloud 升级 Spring Boot 4 经验分享
经验分享·spring boot·后端
秋邱2 小时前
Java面向对象进阶:封装、继承、多态的实现逻辑与实战案例
java·开发语言·后端·spring cloud·ar·restful
架构精进之路2 小时前
一文搞懂什么是 Vibe Coding?
人工智能·后端