Java实现优雅停止线程的有效方法详解

 更新时间:2023年12月06日 16:54:02   作者:代码小人物  
这篇文章主要为大家详细如何安全有效停止 Java 线程的,确保多线程应用程序平稳运行并实现最佳资源管理,感兴趣的小伙伴可以跟随小编一起学习一下

在Java中停止线程意味着在完成其任务之前停止正在进行的操作,本质上是放弃当前操作。

虽然可以使用 Thread.stop() 方法停止线程,但强烈建议不要这样做。虽然它确实终止了正在运行的线程,但此方法被认为是不安全的并且已被弃用。

java中终止线程

在Java中,有3种方法可以终止正在运行的线程:

  • 使用标志:您可以创建一个boolean类型的标志,线程定期检查该标志。当该标志设置为某个值时,线程可以优雅地退出其执行。
  • 使用interrupt()方法:可以使用interrupt()方法向线程发送中断信号。
  • 使用Thread.stop()方法(不推荐):可以使用Thread.stop()方法强行停止正在运行的线程。然而,这种方法不被鼓励并且被认为是不安全的,因为它可能导致应用程序中出现不可预测为。它已被弃用,应该避免。

interrupt方法

使用interrupt()方法不会像带有break语句的for循环一样立即停止循环。它会在当前线程内设置一个停止标志,但它不会立即停止线程。

public class MyThread extends Thread {
    public void run(){
        super.run();
        for(int i=0; i<500000; i++){
            System.out.println("i="+(i+1));
        }
    }
}

public class Run {
    public static void main(String args[]){
        Thread thread = new MyThread();
        thread.start();
        try {
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/*
结果:
...
i=499994
i=499995
i=499996
i=499997
i=499998
i=499999
i=500000
*/

如何检查线程是否处于停止状态

Java中的提供了两种方法:

  • this.interrupted():该方法检测当前线程(调用该方法的线程)是否已被中断。它还具有清除当前线程的中断状态的作用。
  • this.isInterrupted():此方法测试调用它的线程(不一定是当前线程)是否已被中断。它不会清除线程的中断状态。

这两种方法有什么区别?

我们先看一下this.interrupted()方法:

public class MyThread extends Thread {
    public void run(){
        super.run();
        for(int i=0; i<500000; i++){
            i++;
            // System.out.println("i="+(i+1));
        }
    }
}

public class Run {
    public static void main(String args[]){
        Thread thread = new MyThread();
        thread.start();
        try {
            Thread.sleep(2000);
            thread.interrupt();

            System.out.println("stop 1??" + thread.interrupted());
            System.out.println("stop 2??" + thread.interrupted());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/*
---------------------------
结果:
stop 1??false
stop 2??false
*/

可以看到 Run 类中调用Thread对象的 Interrupt() 方法来检查线程对象的线程是否已停止,控制台输出的内容表明线程尚未停止。

这也证实了interrupted()方法,它用于检测当前线程(在此上下文中为主线程)是否已被中断。由于主线程从未被中断过,所以打印的结果是两个false。

如何让主线程产生中断效果

public class Run2 {
    public static void main(String args[]){
        Thread.currentThread().interrupt();
        System.out.println("stop 1??" + Thread.interrupted());
        System.out.println("stop 2??" + Thread.interrupted());

        System.out.println("End");
    }
}
/*
------------------
结果:
stop 1??true
stop 2??false
End
*/

第二个值是 false,因为根据 Interrupted() 方法的官方文档,它会检测当前线程(在这里就是主线程)的中断状态,它会在调用时清除线程的中断状态。

换句话说,如果连续调用它,第二次调用返回 false,因为它已经清除了第一次调用设置的中断状态。

因此,如果连续调用interrupted()两次,第二次调用将返回false,因为第一次调用清除了线程的中断状态。

isInterrupted()

现在让我们看一下 isInterrupted() 方法。

public class Run3 {
    public static void main(String args[]){
        Thread thread = new MyThread();
        thread.start();
        thread.interrupt();
        System.out.println("stop 1??" + thread.isInterrupted());
        System.out.println("stop 2??" + thread.isInterrupted());
    }
}
/*
---------------
结果:
stop 1??true
stop 2??true
*/

isInterrupted() 不会清除中断状态,这就是为什么在输出中看到两个true。

使用异常来停止线程

有了上面获得的知识,就可以在线程中使用for循环来检查线程是否处于停止状态。 如果处于停止状态,后续的代码将不再运行。

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 500000; i++) {
            if (Thread.interrupted()) {
                System.out.println("Thread is interrupted. Exiting...");
                return; //退出
            }
            System.out.println("i="+(i+1));
        }
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
        try {
            Thread.sleep(2000);
            thread.interrupt(); // 设置中断状态
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/*
-------------
结果:
...
i=202053
i=202054
i=202055
i=202056
Thread is interrupted. Exiting...
*/

在停止线程的同时,将继续执行 for 循环之后的任何代码。

改下代码,让我们看一下下面的例子:

public class MyThread extends Thread {
    public void run(){
        super.run();
        for(int i=0; i<500000; i++){
            if(this.interrupted()) {
                System.out.println("Thread is interrupted. Exiting...");
                break;
            }
            System.out.println("i="+(i+1));
        }

        System.out.println("Out of for");
    }
}
/*
结果:
...
i=180136
i=180137
i=180138
i=180139
Thread is interrupted. Exiting...
Out of for
*/

如何解决中断后,代码继续执行的问题

public class MyThread extends Thread {
    public void run(){
        super.run();
        try {
            for(int i=0; i< 500000; i++){
                if(this.interrupted()) {
                    System.out.println("Thread is interrupted. Exiting...");
                    throw new InterruptedException();
                }
                System.out.println("i="+(i+1));
            }

            System.out.println("Out of for");
        } catch (InterruptedException e) {
            System.out.println("In catch...");
            e.printStackTrace();
        }
    }
}
/*
--------------------------------------------------------------------------
结果:
...
i=203798
i=203799
i=203800
Thread is interrupted. Exiting...
In catch...
java.lang.InterruptedException
 at thread.MyThread.run(MyThread.java:13)
*/

线程Sleep怎么停止

如果线程在 sleep() 状态下停止会有什么影响?

public class MyThread extends Thread {
    public void run(){
        super.run();

        try {
            System.out.println("Thread begin...");
            Thread.sleep(200000);
            System.out.println("Thread end...");
        } catch (InterruptedException e) {
            System.out.println("Stop while sleeping" + this.isInterrupted());
            e.printStackTrace();
        }
    }
}
/*
-----------------------------------------------------------------------
 结果:
Thread begin...
Stop while sleeping,the result of isInterrupted() is::false
java.lang.InterruptedException: sleep interrupted
 at java.lang.Thread.sleep(Native Method)
 at thread.MyThread.run(MyThread.java:12)
*/

从打印结果来看,如果线程在睡眠状态下停止,它将抛出InterruptedException异常进入catch块并清除停止状态值,将其设置为false。

强制停止线程

使用 stop() 方法终止线程是一种非常激进的方法。

public class MyThread extends Thread {
    private int i = 0;
    public void run(){
        super.run();
        try {
            while (true){
                System.out.println("i=" + i);
                i++;
                Thread.sleep(200);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Run {
    public static void main(String args[]) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();
        Thread.sleep(2000);
        thread.stop();
    }
}
/*
-----------------------------------------------
  结果:
i=0
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9

Process finished with exit code 0
*/

当调用 stop() 方法时,它会抛出 java.lang.ThreadDeath 异常,但大多数情况下,不需要显式捕获该异常。

public class MyThread extends Thread {
    private int i = 0;
    public void run(){
        super.run();
        try {
            this.stop();
        } catch (ThreadDeath e) {
            System.out.println("In catch");
            e.printStackTrace();
        }
    }
}

public class Run {
    public static void main(String args[]) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();
    }
}

stop() 方法已被弃用,因为强制停止线程可能会阻止某些必要的清理工作完成。

此外,它还可能导致锁定对象解锁,从而导致数据同步问题和数据不一致问题。 由

于 stop() 方法在 JDK 中已被标记为已弃用/过时,因此很明显它存在功能缺陷。 因此,不建议在程序中使用 stop() 方法。

使用 return 来停止线程

将interrupt()方法与return结合起来也可以达到停止线程的效果。

public class MyThread extends Thread {
    public void run(){
        while (true){
            if(this.isInterrupted()){
                System.out.println("The thread has been stopped.");
                return;
            }
            System.out.println("Time: " + System.currentTimeMillis());
        }
    }
}

public class Run {
    public static void main(String args[]) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();
        Thread.sleep(2000);
        thread.interrupt();
    }
}
/*
------------------------------------
结果:...
Time: 1696990194000
Time: 1696990194000
Time: 1696990194000
The thread has been stopped.
*/

但是,仍然建议使用“抛出异常”方法来停止线程,因为它允许您通过在 catch 块中重新抛出异常来传播停止事件。

到此这篇关于Java实现优雅停止线程的有效方法详解的文章就介绍到这了,更多相关Java停止线程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java如何使用interrupt()终止线程

    Java如何使用interrupt()终止线程

    这篇文章主要介绍了Java如何使用interrupt()终止线程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • java 类加载与自定义类加载器详解

    java 类加载与自定义类加载器详解

    本文主要介绍了java 类加载与自定义类加载器。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • JavaWeb基础概念以及与架构之间有哪些区别

    JavaWeb基础概念以及与架构之间有哪些区别

    JavaWeb是基于Java技术栈开发的Web应用,SpringMVC是实现JavaWeb的一种框架,C/S架构和B/S架构的区别主要在客户端形式、开发维护成本、响应速度和跨平台能力,本文介绍JavaWeb基础概念以及与架构之间有哪些区别,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • SpringBoot2.0整合jackson配置日期格式化和反序列化的实现

    SpringBoot2.0整合jackson配置日期格式化和反序列化的实现

    这篇文章主要介绍了SpringBoot2.0整合jackson配置日期格式化和反序列化的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • spring boot mybatis日志输出到控制台的方法实践

    spring boot mybatis日志输出到控制台的方法实践

    在开发过程中我们往往需要打印出SQL语句,这样就方便我们监控问题,本文主要介绍了spring boot mybatis日志输出到控制台的方法实践,具有一定的参考价值,感兴趣的可以了解一下
    2024-05-05
  • Java 关系运算符详情及案例(下)

    Java 关系运算符详情及案例(下)

    这篇文章主要介绍了Java 关系运算符详情及案例的实现,主要续上篇文章,上一篇文章我们讲到“等于”运算符 (==)、“不等于”运算符(!=)、“大于”运算符(>) ,这篇文章继续给大家讲解相关知识,需要的朋友可以参考一下
    2021-12-12
  • Springmvc 4.x利用@ResponseBody返回Json数据的方法

    Springmvc 4.x利用@ResponseBody返回Json数据的方法

    这篇文章主要介绍了Springmvc 4.x利用@ResponseBody返回Json数据的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • java根据扩展名获取系统图标和文件图标示例

    java根据扩展名获取系统图标和文件图标示例

    这篇文章主要介绍了java根据扩展名获取系统图标和文件图标示例,需要的朋友可以参考下
    2014-03-03
  • Java多线程的临界资源问题解决方案

    Java多线程的临界资源问题解决方案

    这篇文章主要介绍了Java多线程的临界资源问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Spring Boot与Spring Security的跨域问题解决方案

    Spring Boot与Spring Security的跨域问题解决方案

    跨域问题是指在Web开发中,浏览器出于安全考虑,限制了不同域名之间的资源访问,本文重点给大家介绍Spring Boot与Spring Security的跨域问题解决方案,感兴趣的朋友一起看看吧
    2023-09-09

最新评论