如何停止一个线程?

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()实例方法,查询线程的中断状态,不会清除标志。
相关推荐
splage7 分钟前
Spring Cloud Data Flow 简介
后端·spring·spring cloud
woniu_maggie10 分钟前
SAP RESTful 接口服务发布教程
后端
用户2794208313211 分钟前
临时解决 Mac SSH 客户端与服务器算法不匹配问题
后端
小锋java123413 分钟前
LangChain4j 来了,Java AI智能体开发再次起飞。。。
java·人工智能·后端
一点一一14 分钟前
nestjs+langchain:Prompt Template
人工智能·后端
Oneslide19 分钟前
低版本kubernetes节点卡死重置恢复方法
后端
spring29979230 分钟前
Spring Boot 实战篇(四):实现用户登录与注册功能
java·spring boot·后端
Rust语言中文社区1 小时前
【Rust日报】Clone:像进程一样 fork 虚拟机的 Rust KVM VMM
开发语言·后端·rust
uzong1 小时前
架构师的必修课:分布式系统发布理论设计要点
后端·架构
程序员cxuan1 小时前
vibe coding 凉了,wish coding 来了
人工智能·后端·程序员