Java多线程之Interrupt中断线程详解

一、测试代码

https://gitee.com/zture/spring-test/blob/master/multithreading/src/test/java/cn/diswares/blog/InterruptTests.java

二、测试

为了方便理解简介中 interrupt 的概念, 写个 DEMO 测试一下

 /**
 * 调用 interrupt 并不会影响线程正常运行
 */
@Test
public void testInvokeInterrupt() throws InterruptedException {
    Thread t1 = new Thread(() -> {
    for (int i = 0; ; i++) {
    log.info(i + "");
    }
    });
    t1.start();
    // 确保 t1.start() 成功执行
    Thread.sleep(1);
    log.info("interrupt 前 t1 interrupt 状态 = {}", t1.isInterrupted());
    t1.interrupt();
    log.info("interrupt 后 t1 interrupt 状态 = {}", t1.isInterrupted());
    log.info("t1 是否存活 = {}", t1.isAlive());
}

三、执行过程描述

  • 首先 main 线程中启动 t1线程
  • t1 线程死循环输出 i++
  • main 线程确保 t1.start() 执行后
  • 打印 t1 线程的线程中断状态
  • 调用 t1.interrupt() 方法使线程中断
  • 打印 t1 线程的线程中断状态

四、输出日志

ignore logs ......
20:29:57.632 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2561
20:29:57.633 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2562
20:29:57.633 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2563
20:29:57.486 [main] INFO cn.diswares.blog.interrupt.InterruptTests - interrupt 前 t1 interrupt 状态 = false
20:29:57.633 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2564
20:29:57.633 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2565
20:29:57.633 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2566
20:29:57.633 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2567
20:29:57.633 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2568
20:29:57.633 [main] INFO cn.diswares.blog.interrupt.InterruptTests - interrupt 后 t1 interrupt 状态 = true
20:29:57.633 [main] INFO cn.diswares.blog.interrupt.InterruptTests - t1 是否存活 = true
20:29:57.633 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2569
20:29:57.633 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2570
20:29:57.633 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - 2571
ignore logs ......

现象描述

  • 调用 t1.interrupt() 执行前线程的 interrupt 状态为 false
  • 调用 t1.interrupt() 执行后线程的 interrupt 状态为 true
  • 线程并没有被中断, 可以成功死循环输出循环次数

五、结论

Interrupt 的真正作用是给线程对象设置一个中断标记, 并不会影响线程的正常运行

六、主要方法释义

new Thread().interrupt()

中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),但实际上只是给线程设置一个中断标志,线程仍会继续运行。

Thread.interrupted()

注意: 这是个静态方法
测试当前线程是否被中断(检查中断标志), 返回一个当前线程的 interrupt 状态, 并重置.
当我们第二次调用时中断状态已经被重置, 将返回一个false
为了方便理解. 写一个 DEMO

七、DEMO

DEMO 非常简单, 调用两次 Thread.interrupted() 观察 main 线程的 interrupt 标记

/**
 * 二次调用 t1.interrupted()
 */
@Test
public void testDoubleInvokeInterrupted () throws InterruptedException {
    Thread.currentThread().interrupt();
    log.info("interrupted1 = {}", Thread.interrupted());
    log.info("interrupted2 = {}", Thread.interrupted());
}

输出日志

21:06:33.397 [main] INFO cn.diswares.blog.interrupt.InterruptTests - interrupted1 = true
21:06:33.402 [main] INFO cn.diswares.blog.interrupt.InterruptTests - interrupted2 = false

八、拓展程序

由于是静态方法. 我们来看一下另一个小程序.

  • 跟之前一样将 t1 程序中断
  • 调用 t1.interrupted()
  • 注意这里是个静态方法
/**
 * 在主线程中调用 t1.interrupted()
 */
@Test
public void testMainInterrupted() throws InterruptedException {
    Thread t1 = new Thread(() -> {
        for (int i = 0; ; i++) {
            log.info("t1 is live");
        }
    });

    t1.start();
    Thread.sleep(1);
    t1.interrupt();
    Thread.sleep(1);
    log.info("{}", t1.interrupted());
}

拓展程序日志

ignore logs ......
21:11:20.504 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - t1 is live
21:11:20.504 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - t1 is live
21:11:20.490 [main] INFO cn.diswares.blog.interrupt.InterruptTests - false
21:11:20.504 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - t1 is live
21:11:20.504 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - t1 is live
21:11:20.504 [Thread-1] INFO cn.diswares.blog.interrupt.InterruptTests - t1 is live
ignore logs ......

拓展程序结论

  • Thread.interrupted() 方法是静态方法
  • 它的实现为 Thread.currentThread(), 获取的是当前正在执行的线程, JDK 原文注释如下

Returns a reference to the currently executing thread object.

Returns: the currently executing thread.

  • 所以这里 t1.interrupted() 返回的其实是 main 线程的线程中断标记

new Thread().isInterrupted()

返回线程对象的中断标记, 不会改变中断标记

  • true: 中断标记存在
  • false: 未设置中断标记状态

优雅的结束一个线程

在 Java 中结束一个线程一般有下面三种手段:

  • (禁用) Thread.stop() 这个方法已经被废弃. 因为这种结束线程的方式过于暴力. 会将当前线程暴力终结. 同时线程持有的锁也都会释放, 并且用户有任何额外的处理来控制, 会导致数据不一致
  • volatile: 外部申明 volatile 开关变量, 当开关条件不满足时结束
  • (推荐) interrupt: 最优雅的方案

九、实战

最初的 DEMO 是个死循环, 那我们对其改造一下. 让它能够优雅的结束

/**
 * 调用 interrupt 并不会影响线程正常运行
 */
@Test
public void testGracefulEndThread() throws InterruptedException {
    Thread t1 = new Thread(() -> {
        for (int i = 0; ; i++) {
            if (Thread.currentThread().isInterrupted()) {
                log.info("{} = true, i = {}", Thread.currentThread().getName(), i);
                break;
            } else {
                log.info("{} = false, i = {}", Thread.currentThread().getName(), i);
            }
        }
    });
    t1.start();
    // 确保 t1.start() 成功执行
    TimeUnit.SECONDS.sleep(1);
    t1.interrupt();
    TimeUnit.SECONDS.sleep(1);
    log.info(t1.getState().toString());
}

到此这篇关于Java多线程之Interrupt中断线程详解的文章就介绍到这了,更多相关Java Interrupt中断线程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

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

    一.interrupt() 说明 interrupt()的作用是中断本线程. 本线程中断自己是被允许的:其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限.这有可能抛出SecurityException异常. 如果本线程是处于阻塞状态:调用线程的wait(), wait(long)或wait(long, int)会让它进入等待(阻塞)状态,或者调用线程的join(), join(long), join(long, int), sleep(long), sl

  • JAVA多线程之中断机制stop()、interrupted()、isInterrupted()

    一,介绍 本文记录JAVA多线程中的中断机制的一些知识点.主要是stop方法.interrupted()与isInterrupted()方法的区别,并从源代码的实现上进行简单分析. JAVA中有3种方式可以终止正在运行的线程 ①线程正常退出,即run()方法执行完毕了 ②使用Thread类中的stop()方法强行终止线程.但stop()方法已经过期了,不推荐使用 ③使用中断机制 线程正常退出没有什么东东,中断机制下面详细介绍,先看下stop()方法的源代码,关键是源代码上的注释.它解释了为什么s

  • Java多线程之中断线程(Interrupt)的使用详解

    interrupt方法 interrupt字面上是中断的意思,但在Java里Thread.interrupt()方法实际上通过某种方式通知线程,并不会直接中止该线程.具体做什么事情由写代码的人决定,通常我们会中止该线程. 如果线程在调用Object类的wait().wait(long)或wait(long, int)方法,或者该类的 join() .join(long) .join(long, int) .sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态

  • java isInterrupted()判断线程的实例讲解

    1.说明 isInterrupted()可以判断当前线程是否被中断,仅仅是对interrupt()标识的一个判断,并不会影响标识发生任何改变(因为调用interrupt()的时候会设置内部的一个叫interrupt flag的标识). 2.实例 public static void main(String[] args) throws InterruptedException{ Thread thread = new Thread(()->{ while (true){} }); thread.

  • 浅谈Java线程Thread之interrupt中断解析

    这一篇我们说说Java线程Thread的interrupt中断机制. 中断线程 线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个程序本身.线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true).它并不像stop方法那样会中断一个正在运行的线程. 判断线程是否被中断 判断某个线程是否已被发送过中断请求,请使用Thread.currentThr

  • 深入分析JAVA 多线程--interrupt()和线程终止方式

    一.interrupt() 介绍 interrupt() 定义在 Thread 类中,作用是中断本线程. 本线程中断自己是被允许的:其它线程调用本线程的 interrupt() 方法时,会通过 checkAccess() 检查权限.这有可能抛出 SecurityException 异常. 如果本线程是处于阻塞状态:调用线程的 wait() , wait(long) 或 wait(long, int) 会让它进入等待(阻塞)状态,或者调用线程的 join(),join(long),join(lon

  • Java处理InterruptedException异常的理论与实践

    前言 对于 InterruptedException,一种常见的处理方式是 "生吞(swallow)" 它 -- 捕捉它,然后什么也不做(或者记录下它,不过这也好不到哪去)-- 就像后面的 清单 4 一样.不幸的是,这种方法忽略了这样一个事实:这期间可能发生中断,而中断可能导致应用程序丧失及时取消活动或关闭的能力. 阻塞方法 当一个方法抛出 InterruptedException 时,它不仅告诉您它可以抛出一个特定的检查异常,而且还告诉您其他一些事情.例如,它告诉您它是一个阻塞(bl

  • interrupt()和线程终止方式_动力节点Java学院整理

    中断线程 线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个程序本身.线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true).它并不像stop方法那样会中断一个正在运行的线程. 判断线程是否被中断 判断某个线程是否已被发送过中断请求,请使用Thread.currentThread().isInterrupted()方法(因为它将线程中断标示位

  • 基于JDK8总结java中的interrupt

    1. interrupt知识点 以下总结基于JDK8 本文不会完整说明interrupt,只会罗列一些比较重要的点.完整了解Thread.interrupt可以看参考资料. 以下的一些理解新的有助于理解参考资料的文章: interrupt方法调用后,针对BLOCKED状态的线程,只是设定中断标志位为true.是否响应中断(感知这个标志位的变化)取决于API的设计.JDK的阻塞IO API.Synchronized同步块.还有Lock中的很多方法(不包括lockInterruptibly)都是不响

  • Java interrupt()方法使用注意_动力节点Java学院整理

    程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的.难以发现的错误. 在本篇文章中,我们针对这些难题之一:如何中断一个正在运行的线程. 背景 中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作.线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个程序.虽然初次看来它可能显得简单,但是,你必须进行一些预警以实现期望的结果.你最好还是牢记以下的几点告诫. 首先,忘掉Thre

随机推荐