相关文章推荐
愤怒的豆芽  ·  WifiNetworkSpecifier.B ...·  6 月前    · 
大方的打火机  ·  failed to execute ...·  10 月前    · 
霸气的小蝌蚪  ·  kafkalistener ...·  1 年前    · 

当我们使用 Thread.stop() 方法去停止线程时,这个方法会报错,抛出了UnsupportedOperationException异常,它在JDK中已经被声明“过期/作废”的方法,显然它在功能上有缺陷,不建议使用。

stop() 方法的源码:

    @Deprecated
    public final void stop() {
        throw new UnsupportedOperationException();
 

该方式是通过抛出ThreadDeath异常来达到停止线程的目的,因此异常抛出可能发生在程序的任何一个地方,报空catch和finally语句快中;
由于抛出ThreadDeath异常,会导致该线程释放所持有的所有锁,而这种释放时间是不可控制的,可能会导致线程安全问题和数据不一样的情况,如在同步代码块中执行数据更新操作时线程突然被停止。

要终止一个线程并不是简单的调用stop()方法,stop()就像linux中的kill一个线程一样,非常暴力,强制线程停止有可能使一些清理工作得不到完成,还有可能会对锁的对象进行解锁,导致数据得不到同步处理,数据不一致,不会保证线程资源的正常释放,可能出现一些不可预期的未知状态,那么避免stop()带来的问题,该怎样去停止线程呢?

二、停止线程的方法

1.使用退出标志

使用退出标志, 使线程正常退出,即当run方法完成后进入线程终止

public void run() {
    while(flag){
        //do something

我们在run方法中加入停止线程的标识flag,在一定时间后停止线程(flag为false),自定义Thread类,例如:

public class MyThread implements Runnable {
    private int number;
    private volatile boolean isStop;//使用volatile关键字修饰,可以在多线程之间共享,成员变量来控制线程的停止
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName() + " == 进入");
        while (!isStop) {
            synchronized (MyThread.class) {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " == " + number);
                    number++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
     * 设置线程标识
     * @param isStop true:停止 false:不停止
    public void stopThread(boolean isStop) {
        this.isStop = isStop;

在main方法中执行

   public static void main(String[] args) {
        try {
            //自定义线程
            MyThread runnable = new MyThread();
            Thread thread = new Thread(runnable, "子线程");
            thread.start();
            //睡5秒
            Thread.sleep(5000);
            //停止线程
            runnable.stopThread(true);
        } catch (InterruptedException e) {
            e.printStackTrace();

根据自定义的MyThread创建子线程,睡5秒后设置线程停止,打印数据如下:

2.使用interrupt()去停止线程

有人会说Thread不是提供了interrupt中断线程的方法吗?很多人认为线程的“中断”就是让线程的停止,在Java中线程的中断(interrupt)只是改变线程的中断状态,对于一般逻辑的线程,如果调用interrupt()方法,对这个线程没有任何影响,但是中断标志变为true,但是并不会停止这个线程的运行。

注意:interrupt()只是改变线程的中断的状态,并没有真正停止线程。

Thread同样提供了相关方法判断线程是否中断:

  • isInterrupted():  测试线程是否已经中断,但是不能清除状态标识。
  • interrupted():     测试当前线程是否中断,静态方法,如果连续执行两次,那么第二次调用将返回false,它执行后具有清除状态的功能,将状态清除变为false;
  public static void main(String[] args) {
        //当前线程
        Thread thread = Thread.currentThread();
        thread.interrupt();
        //打印interrupted()的状态
        System.out.println("interrupted() == " + Thread.interrupted());
        System.out.println("interrupted() == " + Thread.interrupted() + "\n");
        //打印isInterrupted()的状态
        System.out.println("isInterrupted() == " + thread.isInterrupted());
        System.out.println("isInterrupted() == " + thread.isInterrupted());

打印数据如下:

interrupted()判断当前线程状态是否中断,为什么第一个值为true,第二值为false呢?官方文档中对interrupted()的解释是:测试当前线程是否中断状态,并且将状态信息清除,说明interrupted()返回状态的同时,也将该状态信息清除了。而isInterrupted()则是打印线程是否中断的信息,并没有将该信息清除。

自定义线程:

public class MyThread2 extends Thread {
    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 5000; i++) {
            if (this.isInterrupted()) {//获取线程的中断状态
                System.out.println(Thread.currentThread().getName() + ":isInterrupted():" + this.isInterrupted() + " == " + i);
                break;
            System.out.println(Thread.currentThread().getName() + " == " + i);
        System.out.println("=== for下面的语句,线程并没有结束 ===");

main方法中执行:

   public static void main(String[] args) {
        try {
            //自定义线程
            MyThread2 thread = new MyThread2();
            thread.start();
            //睡0.01秒
            Thread.sleep(10);
            //中断线程(不是真正停止线程,而是改变线程中断状态)
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("异常信息 == "+e.getMessage());

打印0-5000的数据,先让Thread2跑了一会就执行interrupt()方法,看看能否中断线程,打印log如下:

从数据可以看到,isInterrupted()默认为false,interrupt()方法将线程的中断状态由false变为true,并且继续往下执行了,所以线程并没有结束。那么我们该怎样去停止线程呢?怎么解决继续执行的问题?

我们可以采用抛异常的方式停止线程(也可以使用return),因为在catch块可以对异常处理进行相关处理,能更好控制流程的运行,不至于流程出现多个return。

自定义线程:

public class MyThread2 extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            System.out.println();
            for (int i = 0; i < 5000; i++) {
                if (this.isInterrupted()) {//获取线程的中断状态
                    System.out.println("isInterrupted():" + this.isInterrupted() + " ========线程已结束,退出线程=========");
                    //break;
                    //return;
                    throw new InterruptedException("抛出异常,线程停止");
                System.out.println(Thread.currentThread().getName() + ":isInterrupted():" + this.isInterrupted() + " == " + i);
            System.out.println("=== for下面的语句,线程并没有结束 ===");
        } catch (Exception e) {
            System.out.println("=== Thread 异常信息 == "+e.getMessage()+" ===");
            e.printStackTrace();

main方法:

   public static void main(String[] args) {
        try {
            //自定义线程
            MyThread2 thread = new MyThread2();
            thread.start();
            //睡0.01秒
            Thread.sleep(10);
            //中断线程(不是真正停止线程,而是改变线程中断状态)
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("main 异常信息 == "+e.getMessage());

在打印0-5000的数据中,线程睡10毫秒后将改变线程中断的状态,根据线程中断的状态来抛出异常或者return相关的处理,log如下:

还有一种情况需要注意的,就是在线程睡眠的时候中断线程

Thread类:执行run方法的时候sleep睡眠2秒

public class MyThread3 extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("=== 线程开始 ===");
            Thread.sleep(2000);
            System.out.println("=== 线程结束 ===");
        } catch (Exception e) {
            System.out.println("=== Thread 异常信息 == "+e.getMessage()+" === isInterrupted():"+this.isInterrupted());
            e.printStackTrace();

main执行方法:

  public static void main(String[] args) {
        try {
            //自定义线程
            MyThread3 thread = new MyThread3();
            thread.start();
            //中断线程
            thread.interrupt();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("main 异常信息 == "+e.getMessage());

打印数据如下:

从控制台的数据可以看到,在睡眠sleep的时候中断线程interrupt(),会立即进入catch的语句,并且将清除停止状态值,变为false,抛出了InterruptedException异常。

对于sleep中的线程,如果你调用了sleep(很长时间),但是现在我想它早点醒过来,那么调用interrupt()使唯一的方法,只有改变它的中断状态,让它从sleep中将控制权转到异常catch语句中,然后再由catch的语句转到正常的逻辑中。

点关注,不迷路

好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是人才。

我是suming,感谢各位的支持和认可,您的点赞、评论、收藏【一键三连】就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !

要想成为一个优秀的安卓开发者,这里有必须要掌握的知识架构,一步一步朝着自己的梦想前进!Keep Moving!

https://artisan.blog.csdn.net/article/details/101174377 https://blog.csdn.net/jiadajing267/article/details/80137006 文章目录一、使用停止标记(volatile变量)二、发起中断、响应中断 (interrupt)三、生产者、消费者要停止线程,得保证任务处理完四、 一、使用停止标记(volatile变量) public class StopThread_1 { public . Thread类听过的stop()不安全已被弃用,通过volatile、AtomicBoolean或者interrupt和isInterrupted方法配合可以优雅的停止线程 终止线程的方法(这里的终止是指让线停止执行):1.stop():使用Thread.stop()方法是强行终止线程,它会释放已经锁定的资源(即释放同步锁),但是会造成程序的不确定性。不推荐使用例如:class User {    private String name ;    private String pwd;    public String getName() {        retu... stop方法抛除ThreadDeath,这个异常会在栈传播,导致所有监视器被释放,这导致不可以预料的后果 * @deprecated This method is inherently unsafe. Stopping a thread with * Thread.stop causes it to unlock all of the monitors that it * has lo  为什么Thread.stop不推荐使用?因为它本质上是不安全的。停止线程会导致它解锁所有已锁定的监视器。(当ThreadDeath异常在堆栈中传播时,监视器被解锁。)如果之前由这些监视器保护的对象中的任何一个处于不一致状态,则其他线程现在可以以不一致的状态查看这些对象。据称这些物体被 损坏。当线程操作受损对象时,可能导致任意行为。这种行为可能微妙且难以检测,或者可能会发音。与其他未经检查的异常不... 这个也是最常见的,指线程体执行完成,线程自动结束。在一般情况下,在 run 方法执行完毕的时候,线程会正常结束。然而,有些线程是后台线程,需要长时间运行,只有在系统满足某些特殊条件后,才能退出这些线程。这时可以使用一个变量来控制循环,比如设置一个 Boolean 类型的标志,并通过设置这个标志为 true 或 false 来控制 while 循环是否退出。 在上面的代码中定义了一个退出的表示 exit,exit 的默认值为 false。在定义 exit 时使用了一个 Java 的关键字 volatile,这 停止线程在java语言中并不像break语句那样干脆,还需要一些技巧性的处理。停止一个线程意味着在线程处理完任务之前停止正在做的操作,也就是放弃当前的操作,虽然这看起来非常简单,但是必须做好防范措施,以便达到预期的效果。停止一个线程可以使用Thread.stop()方法,但不推荐使用此方法,虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是被弃用作废的。大多数情况下,停止一个线程使用Thread.interrupt()方法,但这个方法不会终止一个正在运行的线程,还需要加入一个判断才可以完成 线程对象属于一次性消耗品,一般线程执行完run方法之后,线程就正常结束了,线程结束之后就报废了,不能再次start,只能新建一个线程对象。但有时run方法是永远不会结束的。例如在程序中使用线程进行Socket监听请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。当需要结束线程时,如何退出线程呢? 有三种方法可以结束线程: 1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止 2. 使用interrupt()方法中断线程 3. 使用st 调用stop方法。该方法存在一个问题,JDK官方不推荐使用,该方法在关闭线程时可能不会释放掉monitor的锁,所以建议不要使用该方法结束线程。 (2.1)线程正常结束生命周期 线程运行结束,完成自己的使命之后,就会正常退出,如果线程中的人物耗时比较短,或者时间可控,那么放任它正常结束就好。 (2.2)捕获中断信号关闭线程 代码如下: import java.util.concurrent.TimeUnit; public class InterruptThreadExit 示例代码可以从github上获取https://github.com/git-simm/simm-framework.git 接上篇博客《FutureTask子线程取消执行的状态判断》 一、业务场景:   系统中存在多种场景并发操作事务执行时互锁的情况,导致任务积压,系统崩溃。先做了各场景业务的性能调整,但是并发互锁依然无法避免。于是开始考虑选取调用频繁的同步功能作为死锁的牺牲品...     在开发中,经常会遇到需要停止一个正在运行的线程的场景,以前的做法是通过Thread.stop() 的方式停止具体的线程,但是这个方法目前是被废弃掉的,不推荐使用。不推荐使用的原因如下: 1、该方式是通过立即抛出ThreadDeath异常来达到停止线程的目的,而且此异常抛出可能发生在程序的任何一个地方,包括catch、finally等语句块中。 2、由于抛出ThreadDeatch异常... Python的threading模块松散地基于Java的threading模块。但现在线程没有优先级,没有线程组,不能被销毁、停止、暂停、开始和打断。 Java Thread类的静态方法,被移植成了模块方法。 main thread: 运行python程序的线程 daemon thread 守护线程,如果守护线程之外的线程都结束了。守护线程也会结束,并强行终止整个程序。不要在守护进程中进行资源相关操作。会导致资源不能正确的释放。在非守护进程中使用Event。 Thread 类 (group=None, target=None, name=None, args=(), kwargs={}, *