java中使用interrupt通知线程停止详析

Java中使用interrupt通知线程停止详析

概述

在Java多线程编程中,有时候需要在某个条件满足时中断线程的执行。Java中提供了一种机制,即通过中断(interrupt)的方式通知线程停止。本文将详细阐述Java中使用interrupt通知线程停止的完整攻略。

了解中断机制

在Java中,线程有一个boolean类型的中断标记,初始值为false。当线程调用了interrupt()方法时,中断标记就会被设置为true,表示该线程收到了中断信号。线程在被中断时,可以通过isInterrupted()方法检查中断标记是否被设置了。

如何停止线程

有两种方式停止线程,分别是:

  1. 使用中断(interrupt)机制

    在线程中处理中断信号,以此来停止线程。比如,在线程中不断地检查中断标记,一旦中断标记为true,就立即结束线程。

  2. 使用共享变量

    在线程外部设置一个共享变量,在满足某个条件时,将变量值设置为true。线程在执行时不断检查共享变量的值,如果发现变量值为true,就立即结束线程。

如何使用中断机制停止线程

1. 在线程中检测中断标记

在线程中处理中断信号最常见的方式是不断地检查中断标记,一旦标记为true,就立即结束线程。

public class MyThread extends Thread {
    public void run() {
        while(!isInterrupted()) {
            // do something
        }
    }
}

上面的代码中,线程不断地执行某个任务,同时在每次循环开始时检查中断标记,如果标记为true,则立即退出线程。如果不检查中断标记,那么线程将不会被停止。

2. 在sleep、wait等阻塞方法中捕获中断异常

在使用阻塞方法(如sleep、wait等)时,也可以使用中断机制停止线程。当线程处于sleep、wait等阻塞状态时,调用线程的interrupt()方法将会导致线程抛出InterruptedException异常,从而使线程提前退出阻塞状态。

public class MyThread extends Thread {
    public void run() {
        try {
            while(!isInterrupted()) {
                // do something
                Thread.sleep(1000); // 使用阻塞方法
            }
        } catch (InterruptedException e) {
            // 处理中断异常
        }
    }
}

上面的代码中,线程在循环过程中使用了sleep阻塞方法。由于线程处于阻塞状态,无法在循环中检查中断标记。因此,当线程收到中断信号时,会抛出InterruptedException异常,从而使线程提前退出阻塞状态,进而继续执行线程中的循环所在位置的代码。需要注意的是,抛出InterruptedException异常也清除线程的中断状态。

示例说明

示例一

public class ThreadInterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    System.out.println("线程正在运行...");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        break;
                    }
                }
                System.out.println("线程结束");
            }
        });
        t.start();

        Thread.sleep(5000);
        t.interrupt();
    }
}

上述示例中,主线程创建了一个新线程t,并启动该线程。在新线程t中使用while循环不断输出一行“线程正在运行…”,并使用Thread.sleep()方法暂停1秒钟,从而模拟线程正在工作。

在主线程休眠5秒钟后,调用新线程t的interrupt()方法,线程t会收到中断信号,终止循环并输出“线程结束”。这说明通过使用中断机制,能够实现对线程的安全停止。

示例二

public class ThreadInterrupt2Demo {
    public static void main(String[] args) throws InterruptedException {
        ThreadCounter counter = new ThreadCounter();
        Thread t1 = new Thread(counter, "Thread-1");
        Thread t2 = new Thread(counter, "Thread-2");
        t1.start();
        t2.start();

        Thread.sleep(5000);
        t1.interrupt();
        t2.interrupt();
    }

    private static class ThreadCounter implements Runnable {
        @Override
        public void run() {
            int count = 0;
            while (!Thread.currentThread().isInterrupted() && count < 5) {
                count++;
                System.out.println(Thread.currentThread().getName() + ": " + count);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // 重新设置中断标志
                }
            }
            System.out.println(Thread.currentThread().getName() + "结束");
        }
    }
}

上述示例中,主线程创建了两个新线程t1和t2,并启动这两个线程。线程t1和t2都执行一个Runnable接口实现类ThreadCounter的代码逻辑,主要是在循环中不断输出线程名称和计数器的数值,并使用Thread.sleep()方法暂停1秒钟,从而模拟线程正在工作,计数器的默认初始值为0。

在主线程休眠5秒钟后,调用线程t1和t2的interrupt()方法,线程t1和t2将会收到中断信号,并尝试重新设置自己的中断标记,从而安全终止循环输出线程结束信息。

需要注意的是,由于在线程t1和t2中捕获InterruptedException异常而重新设置中断标记,因此在重新设置中断标记后,循环中使用Thread.sleep()方法时就可能再次触发InterruptedException异常,所以需要再次调用interrupt()方法来设置自己的中断标记。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java中使用interrupt通知线程停止详析 - Python技术站

(0)
上一篇 2023年5月25日
下一篇 2023年5月25日

相关文章

  • Spring循环依赖之问题复现详解

    下面我将详细讲解“Spring循环依赖之问题复现详解”的完整攻略,包含两条示例。 Spring循环依赖问题复现详解 什么是Spring循环依赖问题 当两个或更多的bean需要相互依赖时,就会发生Spring的循环依赖问题。当两个bean之间存在依赖时,容器负责解决依赖关系。但是,当存在循环依赖时,容器不能解决这个问题。 如何复现Spring循环依赖问题 下面…

    Java 2023年5月19日
    00
  • 一文简单了解C# 中的DataSet类

    一文简单了解C#中的DataSet类 在C#中,DataSet类是一种常用的数据容器,可以在内存中存储和操作数据。DataSet类可以包含多个DataTable对象,每个DataTable对象代表一个表格,其中包含多个DataRow对象,每个DataRow对象代表一行数据。本文将详细介绍DataSet类的基本用法和示例应用。 DataSet的基本用法 创建D…

    Java 2023年5月19日
    00
  • Java如何定义Long类型

    Java 中的 Long 类型表示的是一个 64 位的有符号整数,其取值范围为 -2^63 到 2^63-1。 在 Java 中定义 Long 类型可以使用以下两种方式: 1. 直接使用 long 类型的字面量 可以直接定义一个 long 类型的变量,使用 L 或者小写 l 后缀来确保该变量是 Long 类型: long maxValue = 9223372…

    Java 2023年5月26日
    00
  • LibrarySystem图书管理系统开发(一)

    LibrarySystem图书管理系统开发(一) 概述 本文介绍了一种设计和开发图书管理系统的方法,该系统使用Python编程语言和Django框架开发。 需求 我们的图书管理系统需要具备以下功能: 添加/编辑/删除图书 添加/编辑/删除图书分类 借阅/归还图书 搜索图书 管理员登录 设计 数据库设计 我们需要至少两个相关的数据库表来存储数据: Book 和…

    Java 2023年5月30日
    00
  • Java中如何正确重写equals方法

    Java中的equals方法通常需要被重写,以便进行对象之间的比较。正确重写equals方法不仅可以提高代码质量,而且可以避免因错误的比较导致的程序错误。下面是Java中如何正确重写equals方法的完整攻略。 1. 理解equals方法 在开始重写equals方法之前,我们需要先理解equals方法的作用以及如何使用它来比较两个对象。在Java中,equa…

    Java 2023年5月26日
    00
  • javaWeb实现简单文件上传

    下面是“javaWeb实现简单文件上传”的完整攻略。 一、准备工作 在开始之前,需要准备以下工作: 一个支持Servlet、JavaServer Pages(JSP)的JavaWeb环境,如Tomcat、Jetty等。 一个用于上传文件的HTML表单。 编写Java Servlet程序来处理上传文件,并保存在服务器上。 二、HTML表单 HTML表单必须包含…

    Java 2023年5月20日
    00
  • SpringBoot中时间格式化的五种方法汇总

    对于SpringBoot中时间格式化的五种方法汇总,我们可以采取如下方式进行讲解: SpringBoot中时间格式化的五种方法汇总 方法一:使用注解@DateTimeFormat 我们可以在实体类中给日期类型的属性添加@DateTimeFormat注解,参数为指定的日期格式,SpringBoot会根据注解中的格式配置将字符串类型的日期转换成Date类型。示例…

    Java 2023年5月20日
    00
  • Java enum的用法详细介绍及实例代码

    Java中的枚举类型是一种特殊的类,它具有固定数量和固定名称的常量。枚举类型可以让代码更加清晰易懂,避免了使用数字或字符串表示常量时出现的错误。 声明枚举类型 在Java中,声明枚举类型需要使用关键字enum。下面是一个最简单的例子: enum Weekday { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, S…

    Java 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部