如何终止一个线程

news2024/11/26 2:33:17

如何终止一个线程
是使用 thread.stop() 吗?

public class ThreadDemo extends Thread{
    @Override
    public void run() {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("this is demo thread :"+Thread.currentThread().getName());
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadDemo t = new ThreadDemo();
        t.start();
        System.out.println("this is main thread :"+Thread.currentThread().getName());
        t.stop();
    }
}

实际代码中的stop方法是不建议使用的:
t.stop ();

Java 的rt.jar 包中的Thread类的 stop() 源码:


    /**
     * Forces the thread to stop executing.
     * <p>
     * If there is a security manager installed, its <code>checkAccess</code>
     * method is called with <code>this</code>
     * as its argument. This may result in a
     * <code>SecurityException</code> being raised (in the current thread).
     * <p>
     * If this thread is different from the current thread (that is, the current
     * thread is trying to stop a thread other than itself), the
     * security manager's <code>checkPermission</code> method (with a
     * <code>RuntimePermission("stopThread")</code> argument) is called in
     * addition.
     * Again, this may result in throwing a
     * <code>SecurityException</code> (in the current thread).
     * <p>
     * The thread represented by this thread is forced to stop whatever
     * it is doing abnormally and to throw a newly created
     * <code>ThreadDeath</code> object as an exception.
     * <p>
     * It is permitted to stop a thread that has not yet been started.
     * If the thread is eventually started, it immediately terminates.
     * <p>
     * An application should not normally try to catch
     * <code>ThreadDeath</code> unless it must do some extraordinary
     * cleanup operation (note that the throwing of
     * <code>ThreadDeath</code> causes <code>finally</code> clauses of
     * <code>try</code> statements to be executed before the thread
     * officially dies).  If a <code>catch</code> clause catches a
     * <code>ThreadDeath</code> object, it is important to rethrow the
     * object so that the thread actually dies.
     * <p>
     * The top-level error handler that reacts to otherwise uncaught
     * exceptions does not print out a message or otherwise notify the
     * application if the uncaught exception is an instance of
     * <code>ThreadDeath</code>.
     *
     * @exception  SecurityException  if the current thread cannot
     *               modify this thread.
     * @see        #interrupt()
     * @see        #checkAccess()
     * @see        #run()
     * @see        #start()
     * @see        ThreadDeath
     * @see        ThreadGroup#uncaughtException(Thread,Throwable)
     * @see        SecurityManager#checkAccess(Thread)
     * @see        SecurityManager#checkPermission
     * @deprecated This method is inherently unsafe.  Stopping a thread with
     *       Thread.stop causes it to unlock all of the monitors that it
     *       has locked (as a natural consequence of the unchecked
     *       <code>ThreadDeath</code> exception propagating up the stack).  If
     *       any of the objects previously protected by these monitors were in
     *       an inconsistent state, the damaged objects become visible to
     *       other threads, potentially resulting in arbitrary behavior.  Many
     *       uses of <code>stop</code> should be replaced by code that simply
     *       modifies some variable to indicate that the target thread should
     *       stop running.  The target thread should check this variable
     *       regularly, and return from its run method in an orderly fashion
     *       if the variable indicates that it is to stop running.  If the
     *       target thread waits for long periods (on a condition variable,
     *       for example), the <code>interrupt</code> method should be used to
     *       interrupt the wait.
     *       For more information, see
     *       <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
     *       are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
     */
    @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());
    }

源码中标注了已弃用,并且给出来详细的解释和说明:

已弃用
这种方法本质上是不安全的。使用thread.stop停止线程会导致它解锁它锁定的所有监视器(这是未选中的ThreadDeath异常向堆栈上传播的自然结果)。
如果以前受这些监视器保护的任何对象处于不一致状态,则其他线程会看到损坏的对象,从而可能导致任意行为。stop的许多用法应该被简单地修改一些变量以指示目标线程应该停止运行的代码所取代。
目标线程应该定期检查该变量,如果该变量指示要停止运行,则以有序的方式从其运行方法返回。
如果目标线程长时间等待(例如,在条件变量上),则应使用中断方法中断等待。

操作系统在执行stop时,并不知道Java当前的线程情况。
假设run方法中有多条指令在执行。
如果通过stop强制终止,那么可能会导致数据不完整,所以不建议这样使用。

那如何解决呢?


线程中断

可以通过interrupt 来做。但是interrupt不是用来终止的方法,而是发送一个信号,需要对其进行额外处理才可以起到终止的效果。

public class InterruptDemo implements Runnable{
    private int i=0;
    @Override
    public void run() {
        //isInterrupted 默认false
        while(!Thread.currentThread().isInterrupted()){
            System.out.println("this is Thread : "+ (i++) +" - " +Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new InterruptDemo());
        t.start();
        Thread.sleep(1000);//主线程timed_waiting 1秒
        t.interrupt();//设置 interrupted=true
    }
}

执行结果:

......
this is Thread : 69 - Thread-0
this is Thread : 70 - Thread-0
this is Thread : 71 - Thread-0

Process finished with exit code 0

当我们的run方法中,如果存在一个无法终止的操作时(比如while(true)、比如sleep(200000)
它们会使线程阻塞,无法运行,也无法终止,这时要考虑使用interrupt 来中断。


线程复位

在Java线程中,针对阻塞的操作,如果想去唤醒它,它会提供一个中断的异常抛出。
但凡是让线程阻塞的机制(方法),都会抛出中断异常(InterruptedException),需要去处理。


import java.util.concurrent.TimeUnit;

public class InterruptExceptionDemo implements Runnable{
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()){
            try {
                TimeUnit.SECONDS.sleep(200);
            } catch (InterruptedException e) {//触发了线程复位 isInterrupted-> false
                e.printStackTrace();
            }
        }
        System.out.println("thread is end.");
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new InterruptExceptionDemo());
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
    }
}

控台打印结果:
在这里插入图片描述
我们中thread.interrupt() 后,run方法响应来异常,进入catch代码块。
由于触发了线程复位,所以isInterrupted 又重置为 false。
我们需要中catch块中对中断做出处理,可以有的处理方式:

  • 如果不做处理,那么由于中断复位会使线程继续处于sleep状态。
  • 继续中断,将选择权给到run方法,Thread.currentThread().interrupt(); //再次中断
  • 抛出异常。

复位是JVM层面做的,它会在抛异常之前,设置状态为false,即复位。
为什么复位,因为我们处理当前线程的权限应该由线程本身来控制,如果不复位的话,下次循环就会终止,就相当于线程的终止由线程外部来控制了。


线程终止的本质

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

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }
    
    private native void interrupt0();

我们可以看到,Thread的interrupt方法,最终是调动了一个native的interrupt0方法。
而在JVM中,我们可以看到 interrupt0 做了什么。

我们先来看JVM的 jvm.cpp:

JVM_ENTRY(void, JVM_Interrupt(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_Interrupt");

  // Ensure that the C++ Thread and OSThread structures aren't freed before we operate
  oop java_thread = JNIHandles::resolve_non_null(jthread);
  MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock);
  // We need to re-resolve the java_thread, since a GC might have happened during the
  // acquire of the lock
  JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
  if (thr != NULL) {
    Thread::interrupt(thr);
  }
JVM_END

其中最后的 Thread::interrupt(thr) 调用了操作系统层面的中断。
我们找到linux对应的os_linux.cpp 文件:
在这里插入图片描述
进入文件找到interrupt方法如下:

// interrupt support

void os::interrupt(Thread* thread) {
  assert(Thread::current() == thread || Threads_lock->owned_by_self(),
    "possibility of dangling Thread pointer");

  OSThread* osthread = thread->osthread();

  if (!osthread->interrupted()) {
    osthread->set_interrupted(true);//设置一个中断状态
    // More than one thread can get here with the same value of osthread,
    // resulting in multiple notifications.  We do, however, want the store
    // to interrupted() to be visible to other threads before we execute unpark().
    OrderAccess::fence();
    ParkEvent * const slp = thread->_SleepEvent ;//如果是sleep中,唤醒
    if (slp != NULL) slp->unpark() ;
  }

  // For JSR166. Unpark even if interrupt status already was set
  if (thread->is_Java_thread())
    ((JavaThread*)thread)->parker()->unpark();

  ParkEvent * ev = thread->_ParkEvent ;
  if (ev != NULL) ev->unpark() ;

}

上面代码是os的interrupt逻辑,会发现,它不仅仅是设置来一个interrupted变量值,
而且还有 upark的唤醒逻辑。

interrupt()

  • 设置一个共享变量的值 true
  • 唤醒处于阻塞状态下的线程

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

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

相关文章

学了两个月的Java,最后自己什么也不会,该怎么办?

学着学着你会发现每天的知识都在更新&#xff0c;也都在遗忘&#xff0c;可能就放弃了。但是只要自己肯练&#xff0c;肯敲代码&#xff0c;学过的知识是很容易就被捡起来的。等你学透了用不了一年也可以学好 Java的运行原理&#xff1a;Java是一门编译解释型语言&#xff0c;…

片内RAM读写测试实验

片内RAM读写测试实验 概念 RAM是FPGA中常用的基础模块&#xff0c;可广泛用于缓存数据的情况&#xff0c;同样它也是 ROM&#xff0c;FIFO 的基础。 官方已经提供了RAM的IP核进行例化即可。 读写时序&#xff08;具体还是要看官方资料&#xff09;&#xff1a; 过程 创…

华为OD机试真题 用 C++ 实现 - 获取最大软件版本号

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

以太网协议和DNS协议

1.以太网协议报文属性上面的图表示的是整个以太网数据报.目的地址和原地址此处的地址并非是IP地址,而是mac地址.在大小上:mac地址占有6个字节,相比于IPv4,mac可以给全球的每一台设备一个自己的mac地址.在地址的描述上:IP地址描述的是整体路程的起点和终点,而mac地址描述的是相邻…

GAN入门示例

本文参考&#xff1a;pytorch实现简单GAN - 灰信网&#xff08;软件开发博客聚合&#xff09; 上文中pytorch代码执行会有问题&#xff0c;这块本文中已经修复&#xff01; 1、GAN概述 GAN&#xff1a;Generative Adversarial Nets&#xff0c;生成对抗网络。在给定充分的建…

SpringBoot整合Mybatis+人大金仓(kingbase8)

陈老老老板&#x1f9b8;&#x1f468;‍&#x1f4bb;本文专栏&#xff1a;国产数据库-人大金仓&#xff08;kingbase8&#xff09;&#xff08;主要讲一些人大金仓数据库相关的内容&#xff09;&#x1f468;‍&#x1f4bb;本文简述&#xff1a;本文讲一下Mybatis框架整合人…

SAP MM学习笔记1-入库中的发注完了自动设定

SAP点滴学习笔记记录。 今天想整理一下MM模块儿的入库中的发注完了字段儿。 具体业务&#xff1a; 对于某个购买发注票&#xff0c;分批入库之后&#xff0c;剩下几个不想要了&#xff0c;在最后一次入库的时候&#xff0c;如何自动设定购买发注票发注完了字段。 业务流程&a…

LeetCode 160. 相交链表 -- 消除长度差

相交链表 简单 2K 相关企业 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意…

数据服务总线的搭建

关于http协议的基础知识就不介绍了。主要介绍它的报文格式。 如何显示http的报文&#xff1b; 浏览器登录服务端的IP和端口&#xff1a; 服务端接收http客户端发过来的报文&#xff1a;recv(connfd,buffer,1000,0),打印出来。 请求报文格式是请求行&#xff0c;请求头部&#…

系列四、多表查询

一、多表关系 项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结 构&#xff0c;由于业务之间相互关联&#xff0c;所以各个表结构之间也存在着各种联系&#xff0c;基本上分为三种&#xff1a;一对多…

【分组CNN:超分】

Image super-resolution with an enhanced group convolutional neural network &#xff08;基于增强型分组卷积神经网络的图像超分辨率&#xff09; 具有较强学习能力的神经网络被广泛应用于超分辨率问题的求解。然而&#xff0c;CNNs依赖于更深层次的网络结构来提高图像超…

2021.3.3idea创建Maven项目

首先new - project - 找到Maven 然后按下图操作&#xff1a;先勾选使用骨架&#xff0c;再找到Maven-archetype-webapp&#xff0c;选中&#xff0c;然后next填写自己想要创建的项目名&#xff0c;然后选择自己的工作空间①、选择自己下载的Maven插件②、选择选择Maven里的sett…

基于Opencv的缺陷检测任务

数据及代码见文末 1.任务需求和环境配置 任务需求:使用opencv检测出手套上的缺陷并且进行计数 环境配置:pip install opencv-python 2.整体流程 首先,我们需要定义几个参数。 图像大小,原图像比较大,首先将图像resize一下再做后续处理图像阈值处理的相应阈值反转阈值的…

git 的使用方法(上 - 指令)

目录前言&#xff1a;一、Git 是什么&#xff1f;二、SVN与Git的最主要的区别&#xff1f;三、Git 安装四、git 配置1. 创建仓库 - repository2. 配置3. 工作流与基本操作五、Git 的使用流程1. 仓库中创建 1.txt文件2. 查看工作区的文件状态3. 添加工作区文件到暂存区4. 创建版…

c++11 之智能指针

文章目录std::shared_ptrstd::weak_ptrstd::unique_ptr智能指针多线程安全问题在实际的 c 开发中&#xff0c;我们经常会遇到诸如程序运行中突然崩溃、程序运行所用内存越来越多最终不得不重启等问题&#xff0c;这些问题往往都是内存资源管理不当造成的。比如&#xff1a; 有…

浅谈Synchronized的原理

文章目录1.引言2.Synchronized使用方式2.1.普通函数2.2.静态函数2.3.代码块3.Synchronized原理4.Synchronized优化4.1.锁粗化4.2.锁消除4.3.锁升级4.4.无锁4.5.锁偏向锁4.6.轻量级锁4.7.重量级锁5.整个锁升级的过程1.引言 在并发编程中Synchronized一直都是元老级的角色&#…

斗地主洗牌发牌-课后程序(JAVA基础案例教程-黑马程序员编著-第六章-课后作业)

【案例6-4】 斗地主洗牌发牌 【案例介绍】 1.任务描述 扑克牌游戏“斗地主”&#xff0c;相信许多人都会玩&#xff0c;本案例要求编写一个斗地主的洗牌发牌程序&#xff0c;要求按照斗地主的规则完成洗牌发牌的过程。一副扑克总共有54张牌&#xff0c;牌面由花色和数字组成…

Linux 定时任务调度(crontab)

一、Crontab Crontab命令用于设置周期性被执行的指令。该命令从标准输入设备读取指令&#xff0c;并将其存放于“crontab”文件中&#xff0c;以供之后读取和执行。 可以使用Crontab定时处理离线任务&#xff0c;比如每天凌晨2点更新数据等&#xff0c;经常用于系统任务调度。…

【Linux】冯.诺依曼体系结构与操作系统

环境&#xff1a;centos7.6&#xff0c;腾讯云服务器Linux文章都放在了专栏&#xff1a;【Linux】欢迎支持订阅&#x1f339;冯.诺依曼体系结构什么是冯诺依曼体系结构&#xff1f;我们如今的计算机比如笔记本&#xff0c;或者是服务器&#xff0c;基本上都遵循冯诺依曼体系结构…

记一次web漏洞挖掘随笔

最近挖了一些漏洞。虽然重复了&#xff0c;但是有参考价值。这边给大家分享下。漏洞重复还是很难受的&#xff0c;转念一想&#xff0c;人生从不是事事如人意的&#xff0c;漏洞重复忽略&#xff0c;不代表失败。先来后到很重要&#xff0c;出场顺序很重要。1.某站rce 忽略理由…