sleep以及如何正确终止线程

news2025/1/20 10:56:28

Thread.sleep()为什么要抛出中断异常或者放入try-catch中?

因为:在 sleep 的同时也要对外界情况有感知能力,也就是能够响应中断。比如在调用 interrupt() 的时候,其实就是想尽快地结束线程,所以,继续的 sleep 是没有意义的,应该尽快结束。

    public static void main(String[] args) {
        Thread thread = new Thread(){
            @Override
            public void run() {
                try {
                    sleep(10000);
                } catch (InterruptedException e) {
                    System.out.println("sleep 状态被中断了!");
                    e.printStackTrace();
                }
            }
        };
        thread.start();
        // 睡眠两秒后标记中断线程
        try {
            sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

如何正确终止线程?

最直接了断的方法就是调用 stop(),它能直接结束线程的执行,但是已经弃用。

这个方法原本是设计用来停止线程并抛出线程死亡的异常,但是实际上它是不安全的,因为它是直接终止线程解放锁,这很难正确地抛出线程死亡的异常进行处理

所以,更好的方式是设置一个判断条件,然后在线程执行的过程中去判断该条件以去决定是否要进行停止线程,这样就能进行处理并有序地退出这个线程。假如一个线程等待很久的话,那才会直接中断线程并抛出异常。

按照上面所说,我们可以设置一个变量来进行控制,当然,我们可以声明一个 bool 类型进行判断,但是更好的方式是使用 interrupt()

		Thread thread = new Thread(){
            @Override
            public void run() {
                while (!isInterrupted()){
                    System.out.println("Thread is running");
                }
            }
        };
        thread.start();
        // 睡眠两秒后标记中断线程
        try {
            sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

上述代码中值得注意的是,在thread.interrupt() 方法中,只是将线程的 private volatile boolean interrupted设置为true,所以还需要在原线程中通过 isInterrupted() 方法来检查

interrupt() 和 isInterrupted() 源码:

	public void interrupt() {
        if (this != Thread.currentThread()) {
            checkAccess();

            // thread may be blocked in an I/O operation
            synchronized (blockerLock) {
                Interruptible b = blocker;
                if (b != null) {
                    interrupted = true;
                    interrupt0();  // inform VM of interrupt
                    b.interrupt(this);
                    return;
                }
            }
        }
        interrupted = true;
        // inform VM of interrupt
        interrupt0();
    }

	public boolean isInterrupted() {
        return interrupted;
    }

除了上述方法,还可以通过在while中判断 volatile 的boolean变量判断是否终止:

	static class Runner implements Runnable{
        private volatile boolean on = true;
        private long i = 0;
        @Override
        public void run() {
            while (on && !Thread.currentThread().isInterrupted()){
                i++;
            }
            System.out.println("Count i = " + i);
        }
        
        public void cancel(){
            on = false;
        }
    }

中断操作 或 标识位 的方式能使线程在终止时有机会去清理资源,而不是武断地将线程停止,更为安全和优雅

中断清除

一般代码都会这样写:(目的:休眠100毫秒后,判断线程是否被中断,如果未被中断则继续执行业务

	try {
	    Thread.sleep(100);
	} catch (InterruptedException e) {
	    //中断标志已经被清除了
	}
	// Thread.currentThread().isInterrupted():是否被中断了(是否有中断标志)
	if(!Thread.currentThread().isInterrupted()) {
	    //如果没有被中断,则处理业务
	    doSomething();
	}

但是即使线程在sleep期间被中断,我们下面的代码依然会执行。为什么呢?就是因为sleep是会擦除中断标志的,抛异常的同时,该线程的中断状态会被清除:
在这里插入图片描述
如果要实现休眠100毫秒后,判断线程是否被中断,如果未被中断则继续执行业务该怎么办?很简单,我们在本线程再手动中断一次即可 ,这样业务代码就不会执行了:

	try {
	    Thread.sleep(100);
	} catch (InterruptedException e) {
	    //中断标志已经被清除了
	    // 手动中断本线程,将本线程打上中断信号。
	    Thread.currentThread().interrupt();
	}
	// Thread.currentThread().isInterrupted():是否被中断了(是否有中断标志)
	if(!Thread.currentThread().isInterrupted()) {
	    //如果没有被中断,则处理业务
	    doSomething();
	}

interrupted() 和 isinterrupted()

interrupted() 是一个静态方法,它会检查当前线程的中断状态并清除中断状态:如果线程被中断,即中断状态为true,则 interrupted() 方法会返回true,并且会将中断状态重置为false。如果线程没有被中断,即中断状态为false,则 interrupted() 方法会返回false。

而 isInterrupted() 是一个实例方法

代码测试验证对比

实战

List shutdownNow():对所有正在执行的任务线程发送中断信号。等待队列的任务会被返回

		ExecutorService executorService = Executors.newFixedThreadPool(1);
        executorService.execute(()->{
            //任务一直跑
            while (true) {
                System.out.println("1");
            }
        });
        Thread.sleep(3000);
        executorService.shutdownNow();
		System.out.println("shutdown");



		ExecutorService executorService = Executors.newFixedThreadPool(1);
        executorService.execute(()->{
            //任务一直跑
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("1");
            }
        });
        Thread.sleep(3000);
        executorService.shutdownNow();
        System.out.println("shutdown");

shutdownNow 方法的解释:There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. This implementation interrupts tasks via Thread.interrupt; any task that fails to respond to interrupts may never terminate

该方法中最终是调用了每个线程 t 的 interrupt() 方法,所以第一种 while true 会一直输出 1 无法停止。而第二种方法则在3s后停止,最后打印 shutdown

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

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

相关文章

结构体指针变量的使用

1、结构体指针的引用 #include<iostream> using namespace std;struct Student {int num;char name[32]; }; int main() {struct Student stu {1,"张三"};struct Student* p &stu;system("pause"); return 0; } 2、通过结构体指针访问结构体…

使用Scanner接收用户输入

扫描输入的两种方式 Scanner主要提供了两个方法来扫描输入&#xff1a; &#xff08;1&#xff09;hasNextXxx()&#xff1a;是否还有下一个输入项&#xff0c;Xxx可以是Int&#xff0c;Long等代表基本数据类型的字符串。 如果只是判断是否包含下一个字符串&#xff0c;则直…

Spring Boot(六十四):SpringBoot集成Gzip压缩数据

1 实现思路 2 实现 2.1 创建springboot项目 2.2 编写一个接口,功能很简单就是传入一个Json对象并返回 package com.example.demo.controller;import com.example.demo.entity.Advertising; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springf…

Vue3 Axios网络请求简单应用

cd 到项目 安装Axios&#xff1a;cnpm install --save axios post传递参数 需要安装querystring 用于转换参数格式&#xff1a;cnpm install --save querystring 运行示例&#xff1a; 后台接口&#xff1a; GetTestData.java package com.csdnts.api;import java.io.IOExce…

Logic 2逻辑分析器捉到的CAN帧

代码开发环境 逻辑分析仪环境 MCU芯片环境&#xff1a;RH850/U2A16 逻辑分析器(LA)抓到的CAN帧 <完>

ChatGPT与Web3.0:让聊天变得更加有趣和安全

随着数字经济时代的到来&#xff0c;Web3.0应用成为了数字世界的重要组成部分&#xff0c;同时人工智能技术也为Web3.0应用的发展提供了强大的支持。其中&#xff0c;ChatGPT作为一种强大的人工智能技术&#xff0c;在Web3.0应用中发挥着越来越重要的作用。本文将从普通用户的角…

1022.从根到叶的二进制之和

目录 一、题目 二、代码 一、题目 二、代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nu…

CTFHub php://input

1.首先看代码&#xff1a; 这里其实就应该想到的是php://伪协议&#xff1a; php://filter、php://input、php://filter用于读取源码 php://input用于执行php代码 2.其次&#xff0c;判断使用php://input伪协议 而执行php://input伪协议条件是allow_url_include是On 可以先利用…

SAP MM学习笔记24-以评估收货(评价)和非评估收货(非评价)

SAP 中 有评价入库&#xff08;评估收货&#xff09;和非评价入库&#xff08;非评估收货&#xff09;两种入库方式。 一般来说在库品目会采用评价入库&#xff0c;而消费品目&#xff0c;会采用非评价入库。 其实评价入库&#xff0c;非评价入库对外都无所谓的&#xff0c;人…

企业安全体系架构分析:开发安全架构之综合架构

上一期讲述了安全架构的安全性架构。实际上一个综合架构的设计不可能只考虑或者过分的考虑安全性&#xff0c;业务架构与安全架构的综合分析才是一个综合架构应该考虑的事情。那么如何做到鱼与熊掌兼得&#xff1f; 这里涉及一个问题&#xff0c;业务架构应该是什么样子的&…

Redis——Redis.conf详解+Redis持久化(RDB和AOF)+Redis订阅发布

配置文件 redis启动时通过配置文件启动 原生配置文件全文在网上随便搜索一下就能找到了。 单位 配置文件 unit单位 对大小写不敏感 包含 类比import&#xff0c;将其他的配置文件引入 网络 bind 127.0.0.1 // 绑定ip protected-mode yes //是否受保护 po…

4K/8K 超高清实时处理与分发

// 4K/8K超高清时代的来临对于原有系统带来很多新的挑战&#xff0c;存储、带宽、算力成本的大幅增长也是阻碍超高清推广普及的重要原因。LiveVideoStackCon 2023上海站邀请到了腾讯云音视频的刘兆瑞分享在4K/8K超高清视频在实时编码的过程中遇到的困难以及解决方案。 文/刘兆…

构建高性能小程序:优化技巧和最佳实践

第一章&#xff1a;引言 随着移动互联网的快速发展&#xff0c;小程序成为了用户获取信息和进行业务交流的重要平台之一。然而&#xff0c;小程序由于受限于硬件资源和网络环境&#xff0c;开发者需要更加关注性能优化&#xff0c;以提供流畅、高效的用户体验。本文将介绍一些构…

H5前端外包开发框架排名

以下是一些常见的网页前端开发框架以及它们的排名和特点。请注意&#xff0c;随着时间的推移&#xff0c;框架的排名和特点可能会有所变化。不同的项目和团队对于框架的选择会受到多个因素的影响&#xff0c;包括开发团队的技能、项目的规模和要求、性能需求等。北京木奇移动技…

AE使用(一)

打开AE 点击“新建合成” 注意参数&#xff1a;宽度高度是视频是横屏还是竖屏。发布在抖音上&#xff0c;需要做出来竖屏效果&#xff1b;发布在视频网站中需要做出横屏效果。没用特殊需求&#xff0c;默认参数就行。 导入素材&#xff1a;左键双击“导入素材区”的空白部分。 …

将CNKI知网文献条目导出,并导入到Endnote内

将CNKI知网文献条目导出&#xff0c;并导入到Endnote内 目录 将CNKI知网文献条目导出&#xff0c;并导入到Endnote内一、从知网上导出参考文献二、将知网导出的参考文献导入到Endnote 一、从知网上导出参考文献 从知网上导出参考文献过程和步骤如图1所示。 图1 导出的参考文献…

什么是业务敏捷,如何实现业务敏捷?

点击链接了解详情 作者介绍 前言 随着越来越多行业的企业开始关注敏捷&#xff0c;业务敏捷&#xff08;Business Agility&#xff09;成为一个新的热点。毕竟大部分的行业和组织与软件无关&#xff0c;但是依然要实现业务上的敏捷&#xff0c;所以这个系列会主要谈两点&#…

threejs使用gui改变相机的参数

调节相机远近角度 定义相机的配置&#xff1a; const cameraConfg reactive({ fov: 45 }) gui中加入调节fov的方法 const gui new dat.GUI();const cameraFolder gui.addFolder("相机属性设置");cameraFolder.add(cameraConfg, "fov", 0, 100).name(…

Android中的二级列表-ExpandableListView

Android中的二级下拉列表&#xff0c;类似于某Q的分组&#xff0c;采用ExpandableListView实现&#xff0c;适配器方法如下。 先看效果图&#xff1a;有四个分组&#xff0c;每个分组下都有一些子条目&#xff0c;可以跟着父条目展开而显示 实现代码&#xff1a; 一级列表是一…

基于STM32的超声波雷达

视频地址:1.基于STM32的超声波雷达-演示_哔哩哔哩_bilibili 备注:文档最后有所有文件的网盘地址 1. 项目展示 1.1. 最终效果 1.2. 项目硬件 全部必要硬件(左到右): ST-LINK调试器:调试下载程序stm32f103c8t6核心板1.8寸TFT显示器sg90舵机超声波传感器