一、测试代码

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中断线程内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!