zoukankan      html  css  js  c++  java
  • 守护线程

    知识点

    • 什么是守护线程?

        守护线程也是java线程中的一种,和普通线程区别在于,它不会影响JVM的退出。即当所有非守护线程执行结束后,jvm退出,守护线程是否仍在执行不会影响JVM的判断。

    • 守护线程的作用是什么?

        守护线程作为守护者来监控用户线程的状况,比如dubbo monitor,gc。

    • 如何创建一个守护线程  

        在用户线程执行start()之前执行setDeamon(true)方法,该线程就变成了一个守护线程。

        在守护线程中创建的子线程,默认都是守护线程。

    • 守护线程何时结束

        所有的用户线程结束运行后,jvm退出,守护线程自动结束。

    • 守护线程注意事项

        正因为守护线程不知道什么时候就会被关闭,因此不建议参与具体业务执行,防止执行一半被强行结束。

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    守护线程

    Java中的线程分为两种:

    • 用户线程
    • 守护线程

    守护线程,顾名思义,就是用来守护用户线程的线程,如果进程中已经没有用户线程,那么守护线程也会被全部杀死。

    可以理解为守护线程是一个保镖,用来保护和监督用户线程,如果被保护/监督的对象已经没有了,那么它也没有存在的必要。因此会结束守护,即被全部杀死。

    如何创建守护线程

    最常见的是将用户线程转换为守护线程

            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("thread");
                }
            });
            // 将用户线程转换为守护线程
            thread.setDaemon(true);

    同时还有一些其他的工具包也提供了守护线程,如Timer类等。

    DEMO

    先定义一个Thread,用来作为守护线程

    class MyDaemon implements Runnable {
    
        @Override
        public void run() {
            while (true) {
                System.out.println("当前时间:" + new Date());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    再定义一个我们的用户线程类

    class MyThread implements Runnable {
    
        @Override
        public void run() {for (int i = 0; i < 5; i++) {
                System.out.println("用户线程:" + new Date());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    然后是我们的main函数

    这里我们分两个情况来运行:

    1.在main方法中运行守护线程

        public static void main(String[] args) throws InterruptedException {
            System.out.println("main线程:" + new Date());
    
            Thread thread = new Thread(new MyDaemon());
            // 将用户线程转换为守护线程
            thread.setDaemon(true);
            thread.start();
    
        }

    运行结果:

    main线程:Fri Mar 06 14:18:31 CST 2020
    守护线程:Fri Mar 06 14:18:31 CST 2020

    可以看到守护线程并没有一直执行下去,而是在main方法运行结束后被杀死。

    假如我们给main方法增加5秒钟的休眠时间

        public static void main(String[] args) throws InterruptedException {
            System.out.println("main线程:" + new Date());
    
            Thread thread = new Thread(new MyDaemon());
            // 将用户线程转换为守护线程
            thread.setDaemon(true);
            thread.start();
    
            Thread.sleep(5000);
            System.out.println("main线程:" + new Date());
        }

    运行结果:

    main线程:Fri Mar 06 14:20:04 CST 2020
    守护线程:Fri Mar 06 14:20:05 CST 2020
    守护线程:Fri Mar 06 14:20:06 CST 2020
    守护线程:Fri Mar 06 14:20:07 CST 2020
    守护线程:Fri Mar 06 14:20:08 CST 2020
    守护线程:Fri Mar 06 14:20:09 CST 2020
    main线程:Fri Mar 06 14:20:10 CST 2020
    守护线程:Fri Mar 06 14:20:10 CST 2020

    同样的在main方法执行时间内(包括休眠),守护线程一直在正常执行,不断打印时间,main方法结束休眠,运行结束后,守护线程被杀死。

    2.这一次我们在main方法中添加一个用户线程

        public static void main(String[] args) throws InterruptedException {
            System.out.println("main线程:" + new Date());
    
            Thread thread = new Thread(new MyDaemon());
            // 将用户线程转换为守护线程
            thread.setDaemon(true);
            thread.start();
    
            Thread thread2 = new Thread(new MyThread());
            thread2.start();
            System.out.println("main线程:" + new Date());
        }

    运行结果:

    main线程:Fri Mar 06 14:26:00 CST 2020
    守护线程:Fri Mar 06 14:26:00 CST 2020
    main线程:Fri Mar 06 14:26:00 CST 2020
    用户线程:Fri Mar 06 14:26:00 CST 2020
    守护线程:Fri Mar 06 14:26:01 CST 2020
    用户线程:Fri Mar 06 14:26:01 CST 2020
    守护线程:Fri Mar 06 14:26:02 CST 2020
    用户线程:Fri Mar 06 14:26:02 CST 2020
    守护线程:Fri Mar 06 14:26:03 CST 2020
    用户线程:Fri Mar 06 14:26:03 CST 2020
    守护线程:Fri Mar 06 14:26:04 CST 2020
    用户线程:Fri Mar 06 14:26:04 CST 2020
    守护线程:Fri Mar 06 14:26:05 CST 2020

    可以看到,虽然main线程已经执行结束,但是还有一个用户线程仍在执行,因此守护线程并没有随着main线程的结束而被立即杀死,而是一直直到用户线程也执行完成,此时才最终被结束。

    3.这一次,我们改为在守护线程中启动一个用户线程

    守护线程中创建用户线程

    class MyDaemon implements Runnable {
    
        @Override
        public void run() {
            Thread thread = new Thread(new MyThread());
            thread.start();
            System.out.println("当前线程是否守护线程:" + thread.isDaemon());
            while (true) {
                System.out.println("守护线程:" + new Date());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    main方法只启动守护线程

    public static void main(String[] args) throws InterruptedException {
    System.out.println("main线程:" + new Date());

    Thread thread = new Thread(new MyDaemon());
    // 将用户线程转换为守护线程
    thread.setDaemon(true);
    thread.start();
    Thread.sleep(3000);
    }

     运行结果:

    main线程:Fri Mar 06 14:35:25 CST 2020
    当前线程是否守护线程:true
    守护线程:Fri Mar 06 14:35:25 CST 2020
    用户线程:Fri Mar 06 14:35:25 CST 2020
    守护线程:Fri Mar 06 14:35:26 CST 2020
    用户线程:Fri Mar 06 14:35:26 CST 2020
    守护线程:Fri Mar 06 14:35:27 CST 2020
    用户线程:Fri Mar 06 14:35:27 CST 2020

    从结果中可以看到,我们在守护线程中创建的虽然是一个用户线程,也并没有显示的将它设置为一个守护线程,但是在我们的打印结果中,它却表示它是一个守护线程!

    既然它也是守护线程,我们这两个守护线程都在main方法执行的三秒多时间里不断地打印时间,随后随着main方法的结束,而一起结束。

    总结

    由上面的几个例子可知,守护线程是用来作为用户线程的守护者,它随着用户线程的结束而结束(即使守护线程代码是while(true)也会被强制结束)。

    在守护线程中创建的线程,默认都是守护线程(除非用过setDaemon()方法指定它为非守护线程)。

    应用

    守护线程类似于用户线程的一个辅助,因此并不能用来运行一些和业务有关的代码。主要是用来监督当前线程的状态,比如作为监视器来使用(dubbo-monitor)。

  • 相关阅读:
    PostgreSQL中的partition-wise join
    Partition-wise join
    外观模式 门面模式 Facade 结构型 设计模式(十三)
    桥接模式 桥梁模式 bridge 结构型 设计模式(十二)
    组合模式 合成模式 COMPOSITE 结构型 设计模式(十一)
    创建型设计模式对比总结 设计模式(八)
    原型模式 prototype 创建型 设计模式(七)
    单例模式 创建型 设计模式(六)
    建造者模式 生成器模式 创建型 设计模式(五)
    抽象工厂模式 创建型 设计模式(四)
  • 原文地址:https://www.cnblogs.com/yxth/p/12426584.html
Copyright © 2011-2022 走看看