【JavaEE多线程】线程中断 interrupt()

news2025/1/15 7:22:49

系列文章目录

🌈座右铭🌈:人的一生这么长、你凭什么用短短的几年去衡量自己的一生!

💕个人主页:清灵白羽 漾情天殇_计算机底层原理,深度解析C++,自顶向下看Java-CSDN博客

❤️相关文章❤️:清灵白羽 漾情天殇-CSDN博客


目录

系列文章目录

一、终止一个线程

1、标记位终止线程

        1、定义一个共享的标记变量

        2、在线程的执行任务当中周期性检查标记

        3、提供公共方法来设置标记

        4、代码展示标记位终止线程

2、调用interrupt()方法

      1、interrupt()方法

      2、interrupted()方法

      3、isInterrupted()方法

      4、如何判断应该使用哪种方法呢?

      5、什么情况下需要清除中断状态,又为什么要清除中断状态呢?

拓展:

二、线程等待


一、终止一个线程

1、标记位终止线程

        在Java当中通过共享的标记位来终止线程是一种常见的方式,这种方式通常设计一个布尔类型的变量,通常被称为标记或者标志,用来指示线程是否应该终止,线程在执行任务的时候会周期性地检查这个标记,并且标记指示终止时主动退出执行。

        1、定义一个共享的标记变量

        

private volatile boolean shouldTerminate = false;

        这里使用了volatile这个关键字,后续我会为大家详细介绍这个关键字的用法,大家这里先暂时忽略它。

        2、在线程的执行任务当中周期性检查标记

        在线程的任务当中通过周期性地检查标记来确定是否应该被终止,通常在循环当中检查标记。

     

public void run() {
    while (!shouldTerminate) {
        // 执行任务
    }
}

        当这个标记位为true的时候,线程就会退出循环,从而终止执行任务。

        3、提供公共方法来设置标记

        在需要终止线程的时候,提供一个公共方法来设置标记为true。

public void requestTermination() {
    shouldTerminate = true;
}

        4、代码展示标记位终止线程

public class Main{
    private static class MyRunnable implements Runnable{
        private volatile boolean shouldTerminate = false;

        @Override
        public void run() {
            while (!shouldTerminate){
                System.out.println("Thread is running...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("Thread terminated...");
        }
        public void requestTermination(){
            shouldTerminate = true;
        }
    }
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        myRunnable.requestTermination();
    }
}

        在我的示例代码当中,MyRunnable类声明为静态内部类,有以下几个原因:

        1、静态内部类可以直接访问外部类的静态成员

        2、静态内部类的实例化不依赖外部类的实例

        3、静态内部类可以更方便地重用和单独测试:将M有Runnable声明为静态内部类可以使得它更容易被其它类重用,并且可以在不依赖外部类的情况下单独测试。

2、调用interrupt()方法

        我在这里要声明以下只有interrupt方法才能中断线程,其余两个方法只是检查线程当前的线程状态的,这里一定不要混淆。    

      1、interrupt()方法

  • interrupt()方法是Thread类的实例方法,用于向目标线程发送中断信号,即设置目标线程的中断状态为true。
  • 如果目标线程正在阻塞(如调用了sleep()wait()join()等方法),那么会抛出InterruptedException异常。
  • 如果目标线程正在运行,那么只是简单地设置其中断状态为true,线程需要在合适的时机自行检查中断状态并作出响应。

      2、interrupted()方法

        这里的方法其实就是系统为我们自动维护的一个标记位,不需要我们在手动维护了,一会我写代码各位就能够看懂了。

  • interrupted()是Thread类的静态方法,用于检查当前线程的中断状态,并清除中断状态(将中断状态重置为false)。
  • 如果当前线程的中断状态为true,则返回true;否则返回false。
  • interrupted()方法还可以用来检查其他线程的中断状态,即Thread.interrupted()会检查调用它的线程的中断状态。

        3、isInterrupted()方法

  • isInterrupted()是Thread类的实例方法,用于检查目标线程的中断状态,但不会清除中断状态。
  • 如果目标线程的中断状态为true,则返回true;否则返回false。
  • isInterrupted()方法可以用来检查其他线程的中断状态,即通过thread.isInterrupted()来检查指定线程的中断状态。

        总结:

  • interrupt()方法是设置线程中断状态为true的方法,用于向目标线程发送中断信号。
  • interrupted()方法是用于检查当前线程中断状态并清除中断状态。
  • isInterrupted()方法是用于检查目标线程中断状态,但不会清除中断状态。

        4、如何判断应该使用哪种方法呢?

  • 如果你希望向一个线程发送中断信号,让它在合适的时候自行终止执行,那么使用interrupt()方法是比较合适的。这种方式允许线程自行决定如何响应中断信号,可以更安全地终止线程的执行。

  • 如果你需要在一个线程中检查自身的中断状态,并清除中断状态,可以使用interrupted()方法。这种方式适合在执行任务的线程中周期性地检查中断状态,以便及时响应中断信号并执行相应的清理操作。

  • 如果你需要检查其他线程的中断状态,而且不想清除中断状态,可以使用isInterrupted()方法。这种方式适合在一个线程中检查其他线程的中断状态,例如在监控线程池中线程的执行情况时。

        5、什么情况下需要清除中断状态,又为什么要清除中断状态呢?

        清除中断状态通常发生在一些特定的情况下,这些情况通常涉及到线程的异常处理或者线程的复用。

        1、异常处理:在捕获了InterruptedException异常之后,需要清除线程的中断状态。

        2、线程复用:当一个线程执行完某个任务后,可能需要复用该线程来执行其他任务。

        清除中断状态就是将线程判断是否中断的标记位设置为初始值也就是false,清除中断状态就是告诉其它线程这个线程没有被中断。

        在Java中,当线程被中断时,它的中断状态会被设置为true。这个中断状态可以通过调用Thread.interrupted()isInterrupted()方法来检查。

        InterruptedException异常通常是在线程调用了一些可能会抛出InterruptedException的阻塞方法(例如Thread.sleep()、Object.wait()、Thread.join()等)时才会抛出。当线程处于阻塞状态(例如调用了上述方法),而且此时又接收到了中断请求时,这些阻塞方法会抛出InterruptedException异常。这样做的目的是让线程在阻塞状态中响应中断请求,从而提高线程的响应性。因为阻塞的线程无法响应中断请求这个时候抛出异常并且在抛出异常之前系统会自动清除中断状态,让这个目标线程以非中断的状态去响应这个中断。并不是所有的中断请求都会导致InterruptedException异常的抛出。如果线程正在执行非阻塞的任务,而此时接收到中断请求,那么线程就不会抛出InterruptedException异常,而是需要通过检查中断状态来判断是否应该终止执行。

        上述的interrupted()方法是手动清除中断状态,抛出异常这个操作是系统自动清除中断状态,不管怎样目的都是为了清除中断状态让线程继续执行剩余的业务逻辑。

public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
        try {
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    static class MyRunnable implements Runnable{
        @Override
        public void run() {
            System.out.println("子线程开始执行...");
            try {
                Thread.sleep(5000);
                System.out.println("子线程睡眠结束...");
            } catch (InterruptedException e) {
                System.out.println("子线程被中断...");
                e.printStackTrace();
            }
            if (Thread.currentThread().isInterrupted()){
                System.out.println("未被清除!");
            }else {
                System.out.println("已被清除");
            }
        }
    }
}

拓展:

        

public class Main {
    private static class MyRunnable implements Runnable{
        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("线程运行中");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("中断线程");
                }
            }
            System.out.println("线程已经中断");
        }
    }
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        thread.interrupt();
    }
}

        这段代码大家可以试着运行一下,调用interrupt()无法终止线程,当控制台输出中断线程之后,线程会继续执行,这是为什么呢?因为线程在休眠状态下sleep()的时候,系统为了让这个线程响应中断请求,会将他唤醒,并且在抛出异常之前自动清除这个线程的中断状态,也就是这个时候线程的标记位仍然为false,所以这个时候我们必须对这个线程的中断状态进行恢复或者直接使用break关键字终止线程,这里还是推荐大家使用恢复线程中断状态比较好,修改以后的代码如下:

Thread.currentThread().interrupt();

        只需要添加这一行代码即可:

public class Main {
    private static class MyRunnable implements Runnable{
        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("线程运行中");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("中断线程");
                    Thread.currentThread().interrupt();
                    e.printStackTrace();
                }
            }
            System.out.println("线程已经中断");
        }
    }
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        thread.interrupt();
    }
}

        我们使用这行代码将线程的中断状态恢复,线程就可以顺利中断了。


二、线程等待

         

        join()方法是 Thread 类提供的一个方法,用于让一个线程等待另一个线程的结束。具体来说,当一个线程调用另一个线程的 join() 方法时,它会阻塞自己的执行,直到被等待的线程执行结束才继续执行。

这个方法提供了一种线程之间的协作机制,允许一个线程等待另一个线程完成某些重要的工作,然后再继续执行。它通常用于主线程等待子线程的完成,或者一个线程等待其他一组线程的完成。

join() 方法有多个重载形式:

  1. join():使当前线程等待被调用对象的执行完成。
  2. join(long millis):使当前线程等待被调用对象的执行完成,但最多等待指定的毫秒数。
  3. join(long millis, int nanos):使当前线程等待被调用对象的执行完成,但最多等待指定的毫秒数和纳秒数。

使用 join() 方法的一个常见模式是创建一个线程并启动它,然后在主线程中调用该线程的 join() 方法,以等待该线程的完成。例如:

public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start(); // 启动子线程

        try {
            thread.join(); // 主线程等待子线程执行完成
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("子线程执行完成,主线程继续执行...");
    }

    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("子线程开始执行...");
            // 模拟子线程执行一些耗时操作
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程执行完成。");
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1608919.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用FRP配置toml文件搭建内网穿透

需求场景 1、一台外网可访问的有固定ip的云服务器,Ubuntu系统 2、一台外网无法访问的无固定ip的本地家用电脑,Ubuntu系统 需求:将云服务器搭建为一台内网穿透服务器,实现通过外网访问家用电脑(网页)的功能。…

Unity 中(提示框Tweet)

using UnityEngine; using UnityEngine.UI; using DG.Tweening; using System; public class Message : MonoBehaviour {public float dropDuration 0.5f; // 掉落持续时间public float persisterDuration 1f; // 持续显示时间public float dorpHeight;public static Message…

AWS账号注册以及Claude 3 模型使用教程!

哈喽哈喽大家好呀,伙伴们!你听说了吗?最近AWS托管了大热模型:Claude 3 Opus!想要一探究竟吗?那就赶紧来注册AWS账号吧!别担心,现在注册还免费呢!而且在AWS上还有更多的大…

macos知名的清理软件 cleanmymac和腾讯柠檬哪个好 cleanmymacx有必要买吗

MacOS是一款优秀的操作系统,但是随着使用时间的增加,它也会产生一些不必要的垃圾文件,占用磁盘空间和内存资源,影响系统的性能和稳定性。为了保持MacOS的清洁和高效,我们需要使用一些专业的清理软件来定期扫描和清除这…

DePIN 赛道黑马,peaq network 如何打造全新 Web3 物联网?

当 Web2 公司仍对用户数据和资料进行“中心化”的收集与控制时,我们虽享受到了物联网技术的便利,却依旧没有逃脱个人数据和价值所有权的剥夺。由此,Web3 技术开始深入物联网世界,智能家居、智能汽车、智能手机都成为重要发力点&am…

三大层次学习企业架构框架TOGAF

前言 对于一名架构师来讲,如果说编程语言是知识库层次中的入门石,那么企业架构框架则相当于知识库层次中的金字塔尖。如果想成长为企业级的架构师,企业架构框架是必须要攀登的高塔。 目前国内绝大多数企业采用TOGAF标准,因此我们…

XSS漏洞---类型+实战案例+防止

文章目录 目录 文章目录 一.XSS漏洞简介 二.XSS漏洞类型 三.实战案例 反射型XSS 存储型XSS 四.防护措施 一.XSS漏洞简介 XSS漏洞(Cross-Site Scripting)是一种常见的Web应用程序安全漏洞,它允许攻击者在受害者的浏览器中注入恶意脚本。当受…

记录一下flume中因为taildir_position.json因位置不对导致数据无法从kafka被采到hdfs上的问题

【背景说明】 我需要用flume将kafka上的数据采集到hdfs上,发现数据怎么到不了hdfs。 【问题排查】 1.kafka上已有相应的数据 2.我的flume配置文档(没问题), 3.时间拦截器(没问题), 4.JSONObje…

IDEA开启自动导包,自动删包

找到file----------->Settings选项 找到Editor-------->General------------>Auto Import选项 勾选两个选项,在点击Apply,在点击ok 最后就ok了

记录——FPGA的学习路线

文章目录 一、前言二、编程语言2.1 书籍2.2 刷题网站2.3 仿真工具 三、基础知识3.1 专业基础课3.2 fpga相关专业知识 四、开发工具五、动手实验 一、前言 也不是心血来潮想学习fpga了,而是祥哥还有我一个国科大的同学都在往fpga这个方向走 并且看过我之前文章的同…

基于SSH的通讯录管理系统

👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSH的通讯录管理系统拥有两种角色:管理员和用户 管理员:用户管理、公告管理、系别管理、班级管理、通讯信息管理等 用户:拥有管理员中的查看功能…

数据可视化(五):Pandas高级统计——函数映射、数据结构、分组聚合等问题解决,能否成为你的工作备用锦囊?

Tips:"分享是快乐的源泉💧,在我的博客里,不仅有知识的海洋🌊,还有满满的正能量加持💪,快来和我一起分享这份快乐吧😊! 喜欢我的博客的话,记得…

Vast+产品展厅 | Vastbase G100数据库是什么架构?(1)

Vastbase G100是海量数据融合了多年对各行业应用场景的深入理解,基于openGauss内核开发的企业级关系型数据库。 了解Vastbase G100的架构,可以帮助您确保数据库系统的高效、可靠和安全运行。 “Vast产品展厅”将分两期,为您详细讲解Vastbas…

创新指南|利用 AI 工具转变您的内容策略

内容策略涉及规划、创建和管理内容。无论您是在策划博客文章、社交媒体更新还是网站内容,精心制定的内容策略是营销活动成功的关键。然而,如果没有合适的工具,维持强大的内容策略可能会具有挑战性。这就是人工智能(AI) 工具发挥作用的地方&am…

微信小程序四(全局配置和页面配置页面跳转)

全局配置: 小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等 tabBar设置:最少两个最多5个 "tabBar": {"list":[{"pagePath": &qu…

【机器学习300问】76、早停法(Early Stopping)是如何防止过拟合的?

本文带大家介绍一个非常简单的防止过拟合的方法——早停(Early Stopping),首先给出概念,然后通过损失图像来加深对它的理解。 一、早停是什么呀? 早停(Early Stopping)是一种常用的深度学习模型…

STM32F401RCT6电子元器件芯片LQFP64 32位微控制器MCU单片机

STM32F401RCT6微控制器具有丰富的外设接口和较高的处理能力,适用于多种嵌入式应用。以下是一些典型的STM32F401RCT6应用案例: 1. 机器人控制:STM32F401RCT6可以用于制作自动导航机器人、遥控机器人等,负责处理传感器数据、控制电…

【学习】自动化测试有哪些优势和不足

在当今这个数字化时代,软件测试已经成为了任何一款产品成功的关键因素之一。而在诸多的测试方法中,自动化测试凭借着其独特的魅力吸引着越来越多的企业。今天就让我们一起走进自动化测试的世界,探讨它的优势与不足。 一、自动化测试优势 1.…

YoutobeDNN

目录 1. 挑战 2. 系统整体结构 3.召回 4. 排序 5. 训练和测试样本的处理 1. 挑战 (1)规模。很多现有的推荐算法在小规模上效果好,但Youtobe规模很大。 (2)新颖度。Youtobe语料库是动态的,每秒都会有…

【NLP练习】使用Word2Vec实现文本分类

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 一、数据预处理 1. 任务说明 本次加入Word2Vec使用PyTorch实现中文文本分类,Word2Vec则是其中的一种词嵌入方法,是一种用于生成词向量…