首页 > 编程语言 >在Java中如何优雅的停止一个线程?可别再用Thread.stop()了!

在Java中如何优雅的停止一个线程?可别再用Thread.stop()了!

时间:2024-03-13 12:22:26浏览次数:26  
标签:... Java Thread 中断 stop 线程 监控

写在开头

经过上几篇博文的学习,我们知道在Java中可以通过new Thread().start()创建一个线程,那今天我们就来思考另外一个问题:线程的终止
自然终止有两种情况:

1. 线程的任务执行完成;
2. 线程在执行任务过程中发生异常。

start之后,如果线程没有走到终止状态,我们该如何停止这个线程呢?

为什么stop终止不可用

翻看Thread源码后,发现其提供过一个stop()方法,可以用来终止线程,我们看一下它的源码。

【源码解析1】

@Deprecated
    public final void stop() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            checkAccess();
            if (this != Thread.currentThread()) {
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
        // A zero status value corresponds to "NEW", it can't change to
        // not-NEW because we hold the lock.
        if (threadStatus != 0) {
            resume(); // Wake up thread if it was suspended; no-op otherwise
        }

        // The VM can handle all thread states
        stop0(new ThreadDeath());
    }

这个方法使用了@Deprecated修饰,代表着它是废弃的方法,在Java的编码规约中,过时的方法不建议继续使用,并且在这个方法的注释中官方也提示说这是一个不安全的强制恶意中断方法,会破坏线程的原子性。
image

因此,在这里强烈建议大家不要再用stop方法去停止线程了!

如何优雅的停止一个线程

我们知道线程只有从 runnable 状态(可运行/运行状态) 才能进入terminated 状态(终止状态),如果线程处于 blocked、waiting、timed_waiting 状态(休眠状态),就需要通过 Thread 类的 interrupt() 方法,让线程从休眠状态进入 runnable 状态,从而结束线程。

这里就涉及到了一个概念“线程中断”,这是一种协作机制,当其他线程通知需要被中断的线程后,线程中断的状态被设置为 true,但是具体被要求中断的线程要怎么处理,完全由被中断线程自己决定,可以在合适的时机中断请求,也可以完全不处理继续执行下去,这样一来,安全性就得到了保障。

Thread类中提供线程中断的方法如下:

  • Thread.interrupt():中断线程。这里的中断线程并不会立即停止线程,而是设置线程的中断状态为 true(默认是 flase);
  • Thread.currentThread().isInterrupted():测试当前线程是否被中断。线程的中断状态会受这个方法的影响,调用一次可以使线程中断状态变为 true,调用两次会使这个线程的中断状态重新转为 false;
  • Thread.isInterrupted():测试当前线程是否被中断。与上面方法不同的是调用这个方法并不会影响线程的中断状态。

Ok,写了那么多,我们来写一个小的demo测试一下线程中断的方法。

【代码示例】

public class Test {
    public static void main(String[] args) {
        //测试系统监控器
        testSystemMonitor();
    }

    /**
     * 测试系统监控器
     */
    public static void testSystemMonitor() {
        SystemMonitor sm = new SystemMonitor();
        sm.start();
        try {
            //运行 10 秒后停止监控
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("监控任务启动 10 秒后,停止...");
        sm.stop();
    }
}
/*系统监控器*/
class SystemMonitor {

    private Thread t;
    //线程中断标识
    private volatile boolean stop = false;

    /**
     * 启动一个线程监控系统
     */
    void start() {
        t = new Thread(() -> {
            while (!stop) {//判断当前线程是否被打断
                System.out.println("正在监控系统...");
                try {
                    Thread.sleep(3 * 1000L);//执行 3 秒
                    System.out.println("任务执行 3 秒");
                    System.out.println("监控的系统正常!");
                } catch (InterruptedException e) {
                    System.out.println("任务执行被中断...");
                    //重新设置线程为中断状态,保证JVM抛异常情况下,中断状态仍为true。
                    Thread.currentThread().interrupt();
                }
            }
        });
        t.start();
    }
    //线程中断
    void stop() {
        stop = true;
        t.interrupt();
    }
}

在这里我们先创建了一个SystemMonitor类作为系统检测器,每3秒一循环的进行检测,考虑到在Thread.currentThread().isInterrupted()可能在某些情况下中断失效,所以我们这里自定义一个stop变量,作为线程中断的标识,检测线程启动先对标识位进行判断。

然后,我们在Test类中写一个测试方法,调用这个系统监控器,进行检测,并设置10秒后,调用stop方法中断检测线程,将中断标识stop设置为true。启动代码后,我们在控制台可以看到这样的输出:

正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
任务执行 3 秒
监控的系统正常!
正在监控系统...
监控任务启动 10 秒后,停止...
任务执行被中断...

与我们的预期一样,监控线程在执行了3个循环的检测任务后,被成功中断调。到这里,我们就成功的、安全的、优雅的停止了一个线程啦!

结尾彩蛋

如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

image

如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

image

标签:...,Java,Thread,中断,stop,线程,监控
From: https://www.cnblogs.com/JavaBuild/p/18070342

相关文章

  • springboot基于JavaWeb的兽医站管理系统的设计与实现
    摘要随着世界经济信息化、全球化的到来和互联网的飞速发展,推动了各行业的改革。若想达到安全,快捷的目的,就需要拥有信息化的组织和管理模式,建立一套合理、动态的、交互友好的、高效的兽医站管理系统。当前的信息管理存在工作效率低,工作繁杂等问题,基于信息化的兽医站管理目......
  • springboot基于Java的公共交通查询系统的设计与实现
    摘要近年来互联网络的迅猛发展和电子终端设备的普及,赋予了各行业充足的发展空间。公共交通查询系统相比于传统信息技术,时效性是它最大的特色,已经在电子娱乐、经济等中发挥着举足轻重的作用。2019年疫情的爆发,更是短时间内迅速扩大了线上管理系统的规模。尽管服务行业已经......
  • springboot基于Java的远程就医系统
    摘要随着网络科技的不断发展以及人们经济水平的逐步提高,网络技术如今已成为人们生活中不可缺少的一部分,而信息管理系统是通过计算机技术,针对用户需求开发与设计,该技术尤其在各行业领域发挥了巨大的作用,有效地促进了远程就医的发展。然而,由于用户量和需求量的增加,信息过载等......
  • Java学习笔记——第十四天
    常见算法什么是算法算法是解决某个实际问题的过程和方法。排序算法冒泡排序每次都从数组中找出最大值放到数组的后面去。伪代码(升序排序):输入:未排序的数组arr,数组长度length输出:无输出,数组arr原地实现排序1for(i=0;i<length-1;i++)2for(j=0;j<lengt......
  • 基于java+springboot教师工作量管理系统
    基于java+springboot教师工作量管理系统开发语言:Java数据库:MySQL技术:SpringBoot+MyBatis工具:IDEA/Ecilpse、Navicat、Maven系统展示后台展示系统简介本教师工作量管理系统分为管理员还有用户两个权限,管理员可以管理用户的基本信息内容,可以管理公告信息以及公告......
  • JavaScript学习--splice()函数入门与精通
    一、splice入门splice方法:通过删除(两个参数)或替换现有元素(三个参数)或者原地添加新的元素(三个参数)来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。参数:index——必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置(从1开始)。howmany——必需......
  • 浅谈JavaScript
    第一章JavaScript学前准备1.JavaScript简介(1)1992年Nombas的scriptease奠定了JavaScript思想理念;(2)受当时网速的限制,很多操作过程很漫长,如用户注册个账号,先提交到服务器去验证合法性,然后再返回给用户。Netscape发现了这个问题并开发了JavaScript语言,同时微软也开发了一个叫J......
  • 在Java中如何通过优化代码来节省内存
    Java程序的一个常见问题是高内存使用率,这会导致性能问题甚至崩溃。因此,需要使用内存节省技术来优化Java代码并减少内存使用非常重要。选择正确的数据类型:使用适当大小的数据类型可以避免不必要的内存浪费。例如,如果你知道一个整数的取值范围在-128到127之间,那么使用byte类......
  • 《手把手教你》系列技巧篇(三十一)-java+ selenium自动化测试- Actions的相关操作-番外
    1.简介上一篇中,宏哥说的宏哥在最后提到网站的反爬虫机制,那么宏哥在自己本地做一个网页,没有那个反爬虫的机制,谷歌浏览器是不是就可以验证成功了,宏哥就想验证一下自己想法,于是写了这一篇文章,另外也是相对前边做一个简单的总结分享给小伙伴们或者童鞋们。废话不多数,直接进入......
  • java错误:不支持发行版本5
    因为用学校机房的电脑在创建Maven项目时总是报java错误:不支持发行版本5。于是写一篇笔记......