• 两阶段终止模式


    业务

    一个线程不断的去记录系统的信息,当用户按下停止按钮时,启动另一个线程去停止记录线程。

    旧思路

    如何让一个线程 T1 去停止另一个线程 T2 呢?很简单,Thread 为我们提供了一个 API,就是 stop() 方法。

    	public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                while (true) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log.info("记录系统信息...");
                }
            }, "t1");
            t1.start();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Thread t2 = new Thread(() -> {
                log.info("停止记录监控...");
                t1.stop();
            }, "t2");
            t2.start();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述
    使用 stop 方法确实能达到效果,但是却有个致命的问题,当 stop 一个线程时,该线程在哪里被 stop 我们是无法感知的! stop 方法并不稳定,现在已经过时。

    新思路

    可应采取两阶段暂停模式来优雅的停止线程。而两阶段终止模式的关键就在于 interrupt() 方法的使用。
    先介绍下 interrupt() 方法。
    当调用一个线程的 interrupt 方法时,并不会直接让该线程停止,而是给该线程设置一个打断标记,也就是打断标记为 true

    但是注意,如果被打断线程正处于 sleepwaitjoin这三种状态,则会导致被打断的线程抛出 InterruptedException,并清除打断标记,也就是置为 false

    那么我们就可以通过判断打断标记是否为真,来停止线程。

    	public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                Thread currentThread = Thread.currentThread();
                while (true) {
                	if (currentThread.isInterrupted()) {
                        log.info("收尾操作...");
                        break;
                    }
                    try {
                    	// 情况1:睡眠时被打断,打断标记被清空,为 false
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // 打断标记被清空,需要重新打断设置打断标记为 true
                        currentThread.interrupt();
                        log.info("是否被打断: {}", currentThread.isInterrupted());
                        e.printStackTrace();
                    }
                    // 情况2:正常运行时被打断,打断标记为 true
                    log.info("记录系统信息...");
                }
            }, "t1");
            t1.start();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Thread t2 = new Thread(() -> {
                log.info("停止记录监控...");
                t1.interrupt();
            }, "t2");
            t2.start();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述
    可以看到,使用两阶段终止模式可以优雅的停止线程。

    注:sleep 的睡眠被打断会抛出异常,情况打断标记,因此在 catch 块中,需要重新设置打断标记。

  • 相关阅读:
    行政处罚有哪些?
    Unity hub 无法登录问题
    消息订阅与发布
    如何完美解决 IDE升级后启动报错 Internal error. Please refer to https://jb.gg/ide/critical-startup-errors
    CentOS7 NTP客户端的时间同步详解
    R语言和医学统计学系列(1):t检验
    NumPy库的学习
    Qt实战案例(53)——利用QDrag实现拖拽拼图功能
    U-Boot初始化及工作流程分析
    Arthas 监控应用耗时
  • 原文地址:https://blog.csdn.net/weixin_44061521/article/details/125630699