zoukankan      html  css  js  c++  java
  • 安全优雅地停止线程

    首先,先抛出一个问题,该如何安全而优雅地停止线程?

    这道问题的背后,可以很小,小到只是简单终止一个Thread线程,也可以很大,大到例如Dubbo应用的优雅下线......它们其实都有一个共同之处,即非一刀断式地暴力停止某个进程或者线程,而是能够实现在终止过程中,有机会去清理资源,跑完剩余的任务,最后没有任何资源在运行了,才做最后结束,这才算安全而优雅地停止。

    在Java多线程当中,停止线程的方法,其中,有一个已经过期而不建议使用的方式stop(),它停止线程的方式比较简单粗暴,不保证线程的资源正常释放就直接停止了,也就意味着,可能还有线程正在跑,没有运行完成,就直接终结了,这可能会导致程序出现不确定的状态,即死锁状态。

    以stop方式终结线程的方法已经过期,即不再建议使用。

    那么,可有其他方式来优雅地结束线程运行吗?

    这里,可以通过interrupt()方法间接实现。

    为什么说是简接实现呢?

    因为线程执行interrupt()方法并不会直接就终止线程。

    接下来,就简单分析一下,interrupt()是如何实现安全而优雅地终止线程的。

    首先,当执行线程的interrupt()方法后,就会给该线程打上一个中断的标识属性,该标识属性原本是false的,但被打上中断标识后,就会变成true了,这里有点类似volatitle变量的可见性玩法,通过这样的可见性变量,我们就可以设置某种状态,当满足该状态时,就可以跳出程序,提前结束。

    可以通过isInterrupted()方法获取到中断标识属性的状态值,若是true,表示该线程已经被打上中断标识,那么,就可以先清理完资源后,再结束该线程。

    然而,需要注意一点是,这里有一个类似的静态方法,Thread.interrupted(),该方法也可以获取到线程中断状态,但遗憾的是,这个interrupted方法在判断一次线程是否中断后,就会立即对该线程的中断状态复位,即恢复线程到非中断的状态。除此之外,声明抛出InterruptedException的方法,在抛出异常前,也会通过虚拟机将该线程的中断标识状态清除,然后再抛出异常,这时再调用isInterrupted()方法返回的是false。

    这里以代码验证一下——

    public static void main(String[] args) throws InterruptedException {
        Runner one = new Runner();
        Thread countThread = new Thread(one,"CountThread");
        //启动线程
        countThread.start();
        //沉默一秒,先让线程CountThread执行1秒
        TimeUnit.SECONDS.sleep(1);
        //通过interrupt()方法对线程countThread设置中断标识
        countThread.interrupt();
    }
    
    private static class Runner implements Runnable {
        private long i;
        private volatile boolean on = true;
        @Override
        public void run() {
            //当countThread线程标识中断时,Thread.currentThread().isInterrupted()返回的是true,即可结束该线程,同时,停止资源i++的继续运行
            while (!Thread.currentThread().isInterrupted()){
                i++;
            }
            System.out.println("Count i = " + i);
        }
    }
    

    前边提到过,interrupt()标识中断位的玩法,很类似volatitle变量的可见性,反过来,volatitle某种程度上也可以替代interrupt()来判断线程是否需要中断,类似代码如下——

    public static void main(String[] args) throws InterruptedException {
        Runner two = new Runner();
        Thread countThread = new Thread(two,"CountThread");
        countThread.start();
        //睡眠1秒
        TimeUnit.SECONDS.sleep(1);
        two.cancel();
    
    }
    
    private static class Runner implements Runnable {
        private long i;
        private volatile boolean on = true;
        @Override
        public void run() {
            while (on){
                i++;
            }
            System.out.println("Count i = " + i);
        }
    
        public void cancel(){
            on = false;
        }
    }
    

    参考《Java并发编程的艺术》

    作者:朱季谦
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利。
  • 相关阅读:
    u-boot启动流程分析(1)_平台相关部分
    Linux文件系统简介
    PHP将部分内容替换成星号
    自制jQuery焦点图切换简易插件
    一次解决页面特效问题的排查记录
    自制jQuery标签插件
    一套后台管理html模版
    自制jquery可编辑的下拉框
    注册页面的一些记录
    CSS选择器的一些记录
  • 原文地址:https://www.cnblogs.com/zhujiqian/p/15643869.html
Copyright © 2011-2022 走看看