1

什么是守护线程?

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

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

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

可以通过调用 Thread.setDaemon(true)方法将用户线程设置为守护线程。

用户线程执行案例

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代码块将不会执行

守护线程
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代码块的执行~~~~


流逝的傷
17 声望0 粉丝

本人很懒!