守护线程Daemon02

1 JVM线程分类

1.1 分类

  • 用户线程
  • 守护线程 Daemon Thread

1.2 守护线程tips

  • 两者唯一的区别只是jvm判断何时离开的问题(生命周期问题)
  • 当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则不会退出
  • 守护线程是服务用户线程的,在start方法前调用setDaemon(true)把用户线程变成守护线程
  • 典型的守护线程便是java垃圾回收
  • jvm如果都是守护线程,jvm会退出(可以理解main线程执行结束 不再有用户线程)
  • 一个普通的应用程序java.exe代表操作系统启动了一个jvm进程,而一个jvm进程中至少有三个线程: main gc 线程,后两者都是守护线程

2 守护线程生命周期

  1. 只要JVM中尚存任何一个用户线程没有结束,守护线程就不会消亡且会工作
  2. 只有当最后一个用户线程消亡,守护线程会跟着消亡

3 作用

  • 为其他线程的运行提供服务 如GC

4 实验

4.1 实验一:父线程设置为守护线程,那么创建的子线程也是守护线程

  • 子线程

    @Slf4j
    public class ChildThread implements Runnable{
        @Override
        public void run() {
            while (true){
                log.info("I am a child thread..");
                try{
                    TimeUnit.MILLISECONDS.sleep(5000);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
    
  • 父线程改动

@Slf4j
public class DaemonMain {
    public static void main(String[] args) {
        Thread fatherThread = new Thread(){
            @Override
            public void run() {
                Thread childThread = new Thread(new ChildThread());
                childThread.setName("child Thread");
                //childThread.setDaemon(true);
                childThread.start();
                log.info("I am a main thread..");

            }
        };
        fatherThread.setDaemon(true);
        fatherThread.setName("Father Thread");
        fatherThread.start();
        log.info("over..");
    }
}       
  • 输出

    22:27:27.801 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    22:27:27.804 [main] INFO com.uestc.chapter04.DaemonMain - over..
    22:27:27.801 [Father Thread] INFO com.uestc.chapter04.DaemonMain - I am a main thread..
    
  • 详解

    • 父线程设置为守护线程,那么创建的子线程也是守护线程(尽管无线循环)

    • 所以一定要让主线程跑业务,子线程设置为守护线程(主线程不能设置守护线程)

4.2 实验二:被守护线程结束,守护线程也将结束(子线程为守护线程,父线程用户线程)

  • 子线程定义
@Slf4j
public class ChildThread implements Runnable{
    @Override
    public void run() {
        while (true){
            log.info("I am a child thread..");
            try{
                TimeUnit.MILLISECONDS.sleep(5000);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}
  • 主线程定义

    //mainThread 是通过new thread形式创建
    //childthread守护线程是通过接口形式创建
    @Slf4j
    public class DaemonMain {
        public static void main(String[] args) {
               Thread fatherThread = new Thread(){
                @Override
                public void run() {
                    Thread childThread = new Thread(new ChildThread());
                    childThread.setName("child Thread");
                    childThread.setDaemon(true);
                    childThread.start();
                    log.info("I am a main thread..");
    
                }
            };
            //mainThread.setDaemon(true);
            fatherThread.setName("Father Thread");
            fatherThread.start();
            log.info("over..");
        }
    }
    /*
    注意:该案例中是设立子线程为守护线程。如果该案例设置父线程为守护线程,子线程同样会结束,父为守护,子也为守护线程,即案列二
    */
    
  • 输出

    22:19:30.189 [main] INFO com.uestc.chapter04.DaemonMain - over..
    22:19:30.192 [Father Thread] INFO com.uestc.chapter04.DaemonMain - I am a main thread..
    22:19:30.191 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    
  • 详解

    • 这里的main线程不是指代public static void main的这个线程,只是实验变量取名巧合了

    • 尽管你ChildThread守护线程(子线程)是个死循环,但是当它守护的Father Thread线程结束时(I am a main thread…执行完毕),被守护的线程(child Thread)也跟着结束。

4.3 实验三: 整个jvm中只要有用户线程,则守护线程不会结束

  • 子线程定义:

    @Slf4j
    public class ChildThread implements Runnable{
        @Override
        public void run() {
            while (true){
                log.info("I am a child thread..");
                try{
                    TimeUnit.MILLISECONDS.sleep(5000);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
    
  • 主线程定义:

    Thread fatherThread = new Thread(new Runnable(){
                @Override
                public void run(){
                   Thread childThread = new Thread(new ChildThread());
                   childThread.setDaemon(true);
                   childThread.setName("child Thread");
                   childThread.start();
                    log.info("I am a Father thread..");
                }
            });
            fatherThread.setName("Father Thread");
            fatherThread.start();
            Thread otherThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        log.info("I am a other thread");
                        try{
                            TimeUnit.MILLISECONDS.sleep(1000);
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
            }){};
            otherThread.setName("otherThread Thread");
            otherThread.start();
    
  • 输出

    22:53:39.503 [Father Thread] INFO com.uestc.chapter04.DaemonMain - I am a Father thread..//输出一次 father线程执行结束
    22:53:39.504 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    22:53:39.504 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:40.513 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:41.516 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:42.516 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:43.520 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:44.510 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    22:53:44.523 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:45.525 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:46.529 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:47.535 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:48.537 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:49.515 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    22:53:49.540 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:50.541 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:51.543 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:52.548 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:53.549 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:54.517 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    22:53:54.549 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:55.552 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:56.553 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:57.558 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:58.562 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:53:59.522 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    22:53:59.565 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:54:00.570 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:54:01.575 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:54:02.579 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
    22:54:03.583 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread
      .
      .
      .
    
  • 解析

    • 尽管Father Thread线程结束,但是守护线程childThread监控到jvm中的用户线程还有otherThread(在while循环),因此程序会一直打印不会退出。所以说守护线程守护的范围不仅仅是父子,而是整个jvm是否有用户线程

4.4 实验四 指定线程组 守护线程仍然守护

  • 子线程定义: 如上

  • 主线程

    Thread mainThread = new Thread(new Runnable(){
                @Override
                public void run(){
                   Thread childThread = new Thread(new ChildThread());
                   childThread.setDaemon(true);
                   childThread.start();
                   System.out.println("I'm main thread...");
                }
            });
            mainThread.start();
    	
            ThreadGroup selfThreadGroup = new ThreadGroup("selfThreadGroup");
    				//创建线程的时候指定线程所属的线程组-selfThreadGroup
            Thread otherThread = new Thread(selfThreadGroup,new Runnable() {
                @Override
                public void run() {
                    while(true){
                        System.out.println("I am a other thread.");
                        try{
                            TimeUnit.MILLISECONDS.sleep(1000);
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
            }){};
            otherThread.start();
    
    
  • 输出

    I am a other thread.
    I'm main thread...
    I am a child thread.
    I am a other thread.
    I am a child thread.
    I am a other thread.
    I am a child thread.
    I am a other thread.
    I am a child thread.
    

    详解

    • 尽管自定义创建了线程组,但是selfThreadGroup隶属于main的线程组的子(不允许创建孤立线程组)

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KXqMThim-1619536169062)(/Users/yuminghua/Library/Application Support/typora-user-images/image-20200507211111053.png)]

    • 尽管otherThread分配到了ThreadGroup中,但是也属于用户线程,所以也不会结束

4.5 实验五 守护线程采用线程池的方式开启(守护线程将变成用户线程)

  • 子线程: 如上

  • 主线程:

     Thread fatherThread = new Thread(new Runnable(){
                @Override
                public void run()
                {
                    ExecutorService exec = Executors.newCachedThreadPool();
                    Thread childThread = new Thread(new ChildThread());
                    childThread.setDaemon(true);
                    childThread.setName("childThread Thread");
                    exec.execute(childThread);
                    exec.shutdown();
                    log.info("I am a Father thread..");
                }
            });
            fatherThread.setName("fatherThread Thread");
            fatherThread.start();
    }
    
  • 输出

    23:07:18.642 [fatherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a Father thread..
    23:07:18.642 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:07:23.649 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:07:28.651 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:07:33.655 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:07:38.659 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:07:43.661 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:07:48.666 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:07:53.667 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:07:58.667 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:08:03.671 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:08:08.675 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    23:08:13.679 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread..
    .
    .
    .
    
  • 详解

    • 尽管被设置成了守护线程,但是以线程池的方式被开启,该守护线程会变成用户线程(优先级变成Thread.NORM_PRIORITY)

    • 线程池开启的线程都会把守护线程设置失效,且优先级调整成Normal

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wwIehNgl-1619536169064)(/Users/yuminghua/Library/Application Support/typora-user-images/image-20200507214224866.png)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值