如何用Java编写代码来中断一个线程??

简介: 如何用Java编写代码来中断一个线程??

笔者在前面几篇文章中详细的讲解了:线程and进程的区别及其各种对比,在接下来的本篇文章中主要讲解一下:如何中断一个线程~~

所谓的中断就是字面意思:就是让一个线程停下来,线程的终止~

本质上来说,让一个线程终止,办法就一种,让该线程的入口方法执行完毕----》return/抛异常……其他方法也可。

方法1:给线程中设定一个结束标志位(通过该结束表中位来控制方法是否执行完毕)

public class Main5 {
    public static boolean isQuit=false;//成员变量
//线程1与线程2共享同一个内存地址空间(变量也共享)
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            while ( !isQuit){
                System.out.println("heool t---->t线程");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程终止");
        });
        t.start();
        //在主线程中,修改isQuit
        Thread.sleep(3000);//3秒
        isQuit=true;
    }
}

上述代码的运行结果为:

在该段代码中:先启动t这个线程,让t线程先跑,主线程休眠3000毫秒,时间到了,再将特色标记isQuit更改为true,然后导致t线程终止~

思考一下:在上述的代码中:isQuit是成员变量,当我们把该成员变量更改为局部变量后,还能不能正常工作呢??(答案是不能)

比如下述代码:

public class Main5 {
    //成员变量
    //public static boolean isQuit=false;
    public static void main(String[] args) throws InterruptedException {
        boolean isQuit=false;
        boolean finalIsQuit = isQuit;
        Thread t=new Thread(()->{
            while ( !finalIsQuit){
                System.out.println("heool t---->t线程");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程终止");
        });
        t.start();
        //在主线程中,修改isQuit
        Thread.sleep(3000);//3秒
        isQuit=true;
    }
}

该段代码不能正常的工作了~~感兴趣的各位老铁可自行尝试~

该段代码的运行结果为:(一直运行)

线程和线程之间共用同一个内存地址空间(线程1搞的变量线程2也能搞)

对于上述结果不能正常运行的真正原因:变量捕获,

Java要求变量捕获,捕获的变量必须是final,或者“实际final”(变量没有用final修饰,但是代码中没有做出修改~)

当前是使用自己创建的变量,来控制循环,实际上Thread类内置了一个标志位,让我们更方便实现上述效果~

TipS:多线程的代码执行顺序不少从上到下,而是每个线程独立执行!!

public class Main6 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            //currentThread是获取到当前线程的实列
            //此处currentThread得到的对象就是t
            //isInterrupted就算t对象自带的一个标志值
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();//打印出当前异常位置的调用栈
                    break;
                    //加不加break有两种运行结果(可自行查看)
                    //这里需要加break,结束循环
                }
            }
        });
        t.start();
        //主线程
        //主线程并非循环设置,而是只执行了一次~
        Thread.sleep(1000);
        //把t内部的标志位设置成true(默认为false)
        t.interrupt();
    }
}

接下来我们来了解一下:interrupt()方法的作用~

  1. 设置标志位为true
  2. 如果该线程正在阻塞中(比如在执行sleep()方法),此时就会把阻塞状元唤醒,通过抛出异常的方式让sleep()立即结束!

注意:一个非常重要的问题~~

当sleep()被唤醒的时候,sleep()会自动的把isInterrupted()标志位给清空(true---->false),这就导致下次循环仍然可以继续执行了!

本来isInterrupted()是一个false()(未中断),通过调用Interrupt变成已中断,因为已中断导致sleep()被提前唤醒,当sleep()被唤醒……当sleep()被唤醒的时候,sleep()会自动的把isInterrupted()标志位给清空(true---->false),这就导致下次循环仍然可以继续执行了!

在上述的代码中,由于sleep()将true---->false,导致循环继续执行,哪么为啥接下来不抛异常了呢??

调用interrupt,设置中断标志位,sleep()第一次执行,清空了标志位,并抛出异常(这次设置的中断就翻篇了!),sleep()第二次执行,没有中断标志位了!

如果sleep()执行的时候,看到isInterrupted()这个标志位是false,则sleep()正常运行休眠操作,如果当前isInterrupted()这个标志位是true,则sleep()无论是执行了一半还是刚刚执行,都会触发两件事:

  1. 立即抛出异常
  2. 清空标志位为false

然后再进行下次循环到sleep(),由于当前标志位为false,则啥都干不了~~

多线程调试比较麻烦,大家可自行借鉴其他博文进行参考~~~~

为啥sleep()要清空标志位呢??

目的就是为了让线程自身能够对于线程何时结束,有一个明确的控制,当前interrpt()方法的效果不是让线程立即结束,而是告诉他,你该结束了,至于他是否真的要结束,还是等会额结束,都是代码来灵活控制的~,interrupt()只是通知,而不是“命令”

为啥Java这里不强制设定成“命令结束”的操作??比如:只要调用interrupt()就立即结束?

主要是设定成这种非常不友好!!因此线程t合适结束,还得交给t自己比较好~~

相关文章
|
5月前
|
Java 开发工具
【Azure Storage Account】Java Code访问Storage Account File Share的上传和下载代码示例
本文介绍如何使用Java通过azure-storage-file-share SDK实现Azure文件共享的上传下载。包含依赖引入、客户端创建及完整示例代码,助你快速集成Azure File Share功能。
454 6
|
6月前
|
IDE Java 关系型数据库
Java 初学者学习路线(含代码示例)
本教程为Java初学者设计,涵盖基础语法、面向对象、集合、异常处理、文件操作、多线程、JDBC、Servlet及MyBatis等内容,每阶段配核心代码示例,强调动手实践,助你循序渐进掌握Java编程。
796 3
|
6月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
740 3
|
5月前
|
Java 数据处理 API
为什么你的Java代码应该多用Stream?从循环到声明式的思维转变
为什么你的Java代码应该多用Stream?从循环到声明式的思维转变
319 115
|
5月前
|
安全 Java 编译器
为什么你的Java代码需要泛型?类型安全的艺术
为什么你的Java代码需要泛型?类型安全的艺术
231 98
|
5月前
|
安全 Java 容器
告别繁琐判空:Optional让你的Java代码更优雅
告别繁琐判空:Optional让你的Java代码更优雅
|
5月前
|
安全 Java 容器
告别空指针噩梦:Optional让Java代码更优雅
告别空指针噩梦:Optional让Java代码更优雅
465 94
|
5月前
|
Java 编译器 API
java最新版和java8的区别,用代码展示
java最新版和java8的区别,用代码展示
461 43
|
5月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
277 1
|
5月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
295 1