守护线程

什么是守护线程?jvm

其实在Java虚拟机中,线程分为两大类,分别是:用户线程(User Thread)、守护线程(Daemon Thread)ide

守护线程是为其余线程服务的一种特殊线程,它独立于终端而且周期性的执行某种任务或者等待处理某些发生的事件,它依赖于系统。spa

当JVM只存在守护线程时,JVM虚拟机会自动关闭。大多数JVM线程都是守护线程,比较经典的就是垃圾回收线程。线程

能够经过调用 Thread.setDaemon(true)方法将用户线程设置为守护线程。code

用户线程执行案例

public static void main(String[] args) {
    Thread thread = new Thread() {
        @Override
        public void run() {
            try {
                int i = 0;
                while (true) {
                    System.out.println("第" + (++i) + "次在控制台输出信息!");
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    thread.start();
    System.out.println("主线程执行完毕!!!");
    /**
     * 只是一个用户线程, 当主线程执行完毕时,用户线程还会继续执行
     */
}

image-20200317001231737.png

守护线程执行案例

public static void main(String[] args) {
    Thread thread = new Thread() {
        @Override
        public void run() {
            try {
                int i = 0;
                while (true) {
                    System.out.println("第" + (++i) + "次在控制台输出信息!");
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };~~~~
    /**
     * 设置为守护线程
     */
    thread.setDaemon(true);
    thread.start();
    System.out.println("主线程执行完毕!!!");
}

image-20200317001711011.png

这里留下一个疑问,图中当打印“主线程执行完毕!!!”后,如标志主线程已经执行完毕,那么守护线程就不该该打印“第1次在控制台输出信息!”。
这里推测jvm关闭、主线程打印信息、守护线程打印信息应该有一个前后顺序。

为了证实这个推测,咱们在打印打印“主线程执行完毕!!!”后添加手动关闭虚拟机的操做。进程

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread() {
        @Override
        public void run() {
            try {
                int i = 0;
                while (true) {
                    System.out.println("第" + (++i) + "次在控制台输出信息!");
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    /**
     * 设置为守护线程
     */
    thread.setDaemon(true);
    thread.start();
    System.out.println("主线程执行完毕!!!");
    System.exit(1);//JVM退出
}

image-20200317032733289.png

由此可知JVM关闭是最后执行的,而守护线程与主线程执行打印与线程抢占CPU资源有关,至于执行前后顺序可能有所出入。事件

守护线程是否可以影响try-catch-finally中finally代码块的执行呢?

在以前看过一个帖子,守护线程可以影响finally代码块的执行,这里先作一个实验:资源

正常执行
public static void main(String[] args) {
    try {
        System.out.println("执行了try代码块");
        throw new RuntimeException("I am Runtime Exception");
    } catch (Exception e) {
        System.out.println("执行了catch代码块, 错误信息: " + e.getMessage());
    } finally {
        System.out.println("执行了finally代码块");
    }
}

image-20200317003604036.png

异常关闭虚拟机致使finally代码块没法执行
public static void main(String[] args) {
    try {
        System.out.println("执行了try代码块");
        throw new RuntimeException("I am Runtime Exception");
    } catch (Exception e) {
        System.out.println("执行了catch代码块, 错误信息: " + e.getMessage());
        System.exit(1);//异常关闭虚拟机
    } finally {
        System.out.println("执行了finally代码块");
    }
}

image-20200317004123665.png
当手动关闭JVM时,finally代码块将不会执行get

守护线程
public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
        try {
            System.out.println("执行了try代码块");
            throw new RuntimeException("I am Runtime Exception");
        } catch (Exception e) {
            System.out.println("执行了catch代码块, 错误信息: " + e.getMessage());
        } finally {
            System.out.println("执行了finally代码块");
        }
    });

    thread.setDaemon(true);
    thread.start();
    Thread.sleep(1000);
    System.out.println("主线程执行完毕!!!");
}

image-20200317034116156.png
从以上实例可知,守护进程并无finally代码块的执行,那为啥会影响finally代码块的执行呢?虚拟机

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
        try {
            System.out.println("执行了try代码块");
            throw new RuntimeException("I am Runtime Exception");
        } catch (Exception e) {
            System.out.println("执行了catch代码块, 错误信息: " + e.getMessage());
            System.exit(1);
        } finally {
            System.out.println("执行了finally代码块");
        }
    });

    thread.setDaemon(true);
    thread.start();
    Thread.sleep(1000);
    System.out.println("主线程执行完毕!!!");
}

image-20200317035059149.png这是证实的例子,仔细看会发如今catch代码中关闭了JVM,这个原理与异常关闭虚拟机致使finally代码块没法执行同样,所以并不能证实守护线程会影响finally代码块的执行~~~~