Java线程中断的实现过程

 更新时间:2025年06月30日 09:00:27   作者:找不到、了  
这篇文章主要介绍了Java线程中断的实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

线程的调度和执行由操作系统决定,而 Java 通过提供一系列 API 来与操作系统交互,从而实现对线程的控制。

现代操作系统对线程的控制遵循两个核心原则:

1、抢占式调度:操作系统可以强制剥夺线程的 CPU 时间片(如时间片轮转调度)

2、协作式中断:依赖线程主动响应中断信号(Java 的 interrupt())

因此Java 虚拟机(JVM)作为用户态程序,其实是无法直接终止一个线程的。当我们调用 thread.stop() 这类方法时,实际上是在用户态层面发出中断请求,而真正的线程终止还需要操作系统内核的配合。

如下图所示:

Java 线程中断的三种实现方式:

1、volatile 标志位:通过设置标志位,使线程正常退出,能够确保线程根据业务逻辑安全停止。

2、Thread.stop() 方法:已废弃,不推荐使用,因为会导致线程安全问题和资源泄漏。

3、Thread.interrupt() 方法:推荐使用,通过设置中断标志来提示线程停止,能够优雅的停止线程。

1、volatile 标志位

volatile关键字可以确保变量的修改对所有线程立即可见。

通过在共享变量上使用volatile,工作线程可以在运行过程中检查该变量的状态,一旦检测到变化即可清理资源并结束执行。

public class WorkerThread extends Thread {
    privatevolatileboolean running = true;
 
    public void run() {
        int i = 1;
        while (running) { // 检查标志位
            System.out.println("线程运行中: " + i++);
            try {
                Thread.sleep(1000L); // 模拟业务操作
            } catch (InterruptedException e) {
                // 重新设置中断标识
                Thread.currentThread().interrupt();
            }
        }
        System.out.println("线程已优雅停止");
    }
 
    public void cancel() {
        running = false;
    }
 
    public static void main(String[] args) throws InterruptedException {
        WorkerThread thread = new WorkerThread();
        thread.start();
        // 线程运行一段时间
        Thread.sleep(5000L);
 
        // 修改标志位,中断线程
        thread.cancel();
    }
}

输出:

运行结果:

线程运行中: 1
线程运行中: 2
线程运行中: 3
线程运行中: 4
线程运行中: 5
线程已优雅停止

2、stop()强制终止

Thread.stop()方法是 Java 早期提供的一种强制中止线程的方式,该方法会立即终止线程,而不执行清理工作(如释放资源、完成文件操作等),因此容易导致资源泄漏和线程安全问题,已被 Java 官方弃用。

public class WorkerThread extends Thread {
    public void run() {
        int i = 1;
        while (true) {
            System.out.println("线程运行中: " + i++);
            try {
                Thread.sleep(1000L); // 模拟业务操作
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
        WorkerThread thread = new WorkerThread();
        thread.start();
        // 线程运行一段时间
        Thread.sleep(5000L);
 
        // 调用 stop 方法,强制终止线程
        thread.stop();
        System.out.println("线程已强制终止");
    }
}
运行结果:

线程运行中: 1
线程运行中: 2
线程运行中: 3
线程运行中: 4
线程运行中: 5
线程已强制终止

为什么 stop() 方法会被废弃呢? JavaDoc 中Why is Thread.stop deprecated?这篇官方文档解释了其被废弃的原因。

总结如下:

  • 不可控的资源释放:线程可能持有锁或资源,强制终止可能导致资源泄漏。
  • 数据不一致:线程可能在执行关键操作时被中断,导致数据损坏。
  • 难以调试:强制终止可能引发不可预测的异常。

3、interrupt() 协作式中断

因为Thread.stop()中断线程的粗暴性,Java 官方已经废弃了该方法,那么官方还有没有其它更优雅的方案来中断线程呢?答案是有的:那就是使用interrupt()协作式中断。

什么是协作式中断?

协作式中断就是区别于 Thread.stop(),它是非强制且需要配合的。

非强制性:

interrupt() 方法不会强制终止线程,而是通过设置中断标志来通知线程应该停止。线程可以选择中断,也可以忽略这个中断请求,继续执行。

需要配合:

使用 interrupt() 方法,线程需要主动检查中断标志,或者在阻塞方法中处理 InterruptedException,才能正常响应中断请求。这种机制是需要线程和中断请求者之间相互“配合”的。

通过示例来演示下协作式中断:

public class WorkerThread extends Thread {
 
    @Override
    public void run() {
        int i = 1;
        while (!Thread.currentThread().isInterrupted()) { // 显式检查中断状态
            System.out.println("线程运行中: " + i++);
            try {
                Thread.sleep(1000L); // 模拟业务操作
            } catch (InterruptedException e) {
                System.out.println("捕获到中断异常,但线程继续运行!");
//                Thread.currentThread().interrupt();
            }
        }
        System.out.println("线程已优雅停止");
    }
 
    public static void main(String[] args) throws InterruptedException {
        WorkerThread thread = new WorkerThread();
        thread.start();
        Thread.sleep(5000L); // 主线程等待5秒
 
        // 请求线程中断
        thread.interrupt();
        System.out.println("主线程请求线程中断");
    }
}
 运行结果:

线程运行中: 1
线程运行中: 2
线程运行中: 3
线程运行中: 4
线程运行中: 5
主线程请求线程中断
捕获到中断异常,但线程继续运行!
线程运行中: 6
线程运行中: 7

可以看到,main() 方法中已经请求了线程中断,但是线程并没有被中断,还是继续执行下去了,为什么?

interrupt() 方法被调用时,线程的中断标志会被设置为 true。它的调用只是传递了一个中断信号,线程本身不会立即停止执行。

它需要通过检查中断标志(如使用 Thread.currentThread().isInterrupted())来决定是否停止当线程。

并且当线程处于以下阻塞方法(如 sleep()、wait()、join())时,

JVM 会做两件事:1.抛出 InterruptedException 异常;2.清除中断标志,重新设置为 false。

那么,当我们在程序中捕获到 InterruptedException 异常时,我们需要做出明确的选择:

处理异常并终止线程的执行;重新设置中断标识让上层逻辑感知到。

上边的示例中,我们在捕获了 InterruptedException 异常后,这时中断标志已经被重置,而程序中却没有做任何的处理,导致了在下一轮的循环判断中,检测的中断状态不对,所以线程没有按预期执行中断。

正例

public class WorkerThread extends Thread {
 
    @Override
    public void run() {
        int i = 1;
        while (!Thread.currentThread().isInterrupted()) { // 显式检查中断状态
            System.out.println("线程运行中: " + i++);
            try {
                Thread.sleep(1000L); // 模拟业务操作
            } catch (InterruptedException e) {
                // 重新设置中断标志,通知上层逻辑进行中断处理
                System.out.println("线程被中断!");
                Thread.currentThread().interrupt();
            }
        }
        System.out.println("线程已优雅停止");
    }
 
    public static void main(String[] args) throws InterruptedException {
        WorkerThread thread = new WorkerThread();
        thread.start();
        Thread.sleep(5000L); // 主线程等待5秒
 
        // 请求线程中断
        thread.interrupt();
        System.out.println("主线程请求线程中断");
    }
}
运行结果:

线程运行中: 1
线程运行中: 2
线程运行中: 3
线程运行中: 4
线程运行中: 5
主线程请求线程中断
线程被中断!
线程已优雅停止

在这个示例中,我们在捕获到异常后,正确的恢复了中断标志,线程优雅地被中断。

关于在线程运行状态会出现的方法,可参考如下:

总结

在实际开发中,推荐使用 volatile 标志位和 thread.interrupt() 协作式中断来中止线程。这两种方式能够确保线程的安全和资源的正确释放,避免线程不安全和资源泄漏问题。

如下图所示:

thread.stop() 方法由于其强制性和不安全性,已被废弃,不推荐使用。通过合理使用协作式中断机制,可以实现线程的优雅停止,提高程序的健壮性和可靠性。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Maven dependencies与dependencyManagement的区别详解

    Maven dependencies与dependencyManagement的区别详解

    这篇文章主要介绍了Maven dependencies与dependencyManagement的区别详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-04-04
  • Java如何跳出当前多重循环你知道吗

    Java如何跳出当前多重循环你知道吗

    这篇文章主要为大家介绍了Java跳出当前多重循环,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • java基本教程之join方法详解 java多线程教程

    java基本教程之join方法详解 java多线程教程

    本文对java Thread中join()方法进行介绍,join()的作用是让“主线程”等待“子线程”结束之后才能继续运行,大家参考使用吧
    2014-01-01
  • IDEA如何配置本地tomcat启动项目

    IDEA如何配置本地tomcat启动项目

    这篇文章主要介绍了IDEA如何配置本地tomcat启动项目问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • java图片压缩工具类

    java图片压缩工具类

    这篇文章主要为大家详细介绍了java图片压缩工具类,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-02-02
  • Spring 中使用 Validation 注解校验参数的方法

    Spring 中使用 Validation 注解校验参数的方法

    本文介绍了如何在Spring中使用Validation注解进行参数校验,包括引入依赖、简单示例、常见校验注解分类与说明、分组校验和自定义校验,通过这些方法,可以方便地对Controller、Service等层面的参数进行校验,确保数据的合法性和一致性,感兴趣的朋友跟随小编一起看看吧
    2024-11-11
  • spring retry实现方法请求重试的使用步骤

    spring retry实现方法请求重试的使用步骤

    这篇文章主要介绍了spring retry实现方法请求重试及使用步骤,本文分步骤通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • JPA之使用JPQL语句进行增删改查

    JPA之使用JPQL语句进行增删改查

    这篇文章主要介绍了JPA之使用JPQL语句进行增删改查,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • Java动态替换properties文件中键值方式

    Java动态替换properties文件中键值方式

    这篇文章主要介绍了Java动态替换properties文件中键值方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • 使用Java和Redis实现高效的短信防轰炸方案

    使用Java和Redis实现高效的短信防轰炸方案

    在当今互联网应用中,短信验证码已成为身份验证的重要手段,然而,这也带来了"短信轰炸"的安全风险 - 恶意用户利用程序自动化发送大量短信请求,导致用户被骚扰和企业短信成本激增,本文将详细介绍如何使用Java和Redis实现高效的短信防轰炸解决方案,需要的朋友可以参考下
    2025-04-04

最新评论