zoukankan      html  css  js  c++  java
  • java中守护线程的一些概念和用法

    网上的资料中,守护线程的功能一般都是“只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束是,守护线程随着JVM一同结束工作,Daemon作用是为其他线程提供便利服务,守护线程最典型的应用就是GC(垃圾回收器),他就是一个很称职的守护者。”
    可是,我发现真实情况却不是描述的这么回事,因为我对java也不懂,所以在此记录一下守护线程中的一些问题。

    我的思路是:
    在main线程中建立两个线程,一个线程A只打印一行信息就退出,它被设置成守护线程,另一个线程B通过sleep和循环来进行时间控制,让它多运行一会,他被设置成非守护线程。如果按照上面的说明,我认为线程A怎么说也要和线程B的消亡时间是一样的。实际情况却不是这样的。
    下面是代码:

    文件 ThreadDaemon.java

    package javaStudy.threadStudy;
    
    import java.util.Date;
    
    public class ThreadDaemon {
        public static void main(String[] args) {
            // Thread.currentThread().setDaemon(true);
            // Thread.currentThread().start();
            // 系统的main函数使用一个主线程,主线程不是守护线程,也不能被设置成守护线程
            System.out.println(Thread.currentThread().getName() + "	process begin	" + (new Date()) + "	"
                    + Thread.currentThread().isDaemon() + "	thread amount	"
                    + Thread.currentThread().getThreadGroup().activeCount());
            showThreadName();
            // 新建一个线程,并将其设置成守护线程,他的操作仅仅是打印一行信息。
            Thread t = new Thread(ThreadDaemon::daemonPrint);
            t.setDaemon(true);
            t.start();
            System.out.println(Thread.currentThread().getName() + "	after create thread A	" + (new Date()) + "	"
                    + Thread.currentThread().isDaemon() + "	thread amount	"
                    + Thread.currentThread().getThreadGroup().activeCount());
            showThreadName();
    
            // 再建立一个线程,将其设置成用户线程,即非守护线程。让他多执行一会。
            try {
                Thread.sleep(1000 * 3);
                Thread thread2 = new Thread(ThreadDaemon::print);
                thread2.setDaemon(false);
                thread2.start();
                System.out.println(Thread.currentThread().getName() + "	after create thread B	" + (new Date()) + "	"
                        + Thread.currentThread().isDaemon() + "	thread amount	"
                        + Thread.currentThread().getThreadGroup().activeCount());
                showThreadName();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println(Thread.currentThread().getName() + "	Exit:" + "	" + (new Date()) + "	"
                    + Thread.currentThread().isDaemon() + "	thread amount "
                    + Thread.currentThread().getThreadGroup().activeCount());
            showThreadName();
            // System.exit(0) 是退出jvm。如果有此代码,则子线程也会直接随着主线程而退出。如果没有此代码,jvm会在子线程结束的时候而退出。
            // System.exit(0);
        }
    
        // 用户线程的调用
        public static void print() {
            int counter = 1;
            while (counter < 5) {
                try {
                    Thread.sleep(3 * 1000); // sleep for 10 seconds
                    System.out.println(Thread.currentThread().getName() + "	before Counter:" + counter++ + "	"
                            + (new Date()) + "	" + Thread.currentThread().isDaemon() + "	thread amount "
                            + Thread.currentThread().getThreadGroup().activeCount());
                    Thread.sleep(3 * 1000); // sleep for 10 seconds
                    System.out.println(Thread.currentThread().getName() + "	after Counter:" + counter++ + "	"
                            + (new Date()) + "	" + Thread.currentThread().isDaemon() + "	thread amount "
                            + Thread.currentThread().getThreadGroup().activeCount());
                    showThreadName();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        // 守护线程的调用
        public static void daemonPrint() {
            try {
                Thread.sleep(6 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println(
                    Thread.currentThread().getName() + "	" + (new Date()) + "	" + Thread.currentThread().isDaemon()
                            + "	thread amount " + Thread.currentThread().getThreadGroup().activeCount());
            showThreadName();
        }
    
        // 显示线程名称
        public static void showThreadName() {
            ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
            int noThreads = currentGroup.activeCount();
            Thread[] lstThreads = new Thread[noThreads];
            currentGroup.enumerate(lstThreads);
            for (int i = 0; i < noThreads; i++) {
                System.out.println("==============="+lstThreads[i].getName() + "	" + lstThreads[i].isDaemon());
            }
        }
    }

    以上代码,我根据程序休眠的时间,让主线程先退出,然后发现守护线程却在第二个退出的。因为他不是死循环,所以提前退出了?这么说来,如果一个线程要想是守护线程的话,他必须是死循环?也就是说,从程序表面看,守护线程一定要比用户线程存活的久一点?这么说来,将一个理论上活的更久的线程,设置成守护线程,仅仅是让它自动和用户线程一起消亡罢了。实际上,通过延长上面代码的daemonPrint()的sleep的时间,也可以验证守护线程会和用户线程一起消亡。

    下面是程序的日志:

    main process begin Tue Oct 16 17:17:29 CST 2018 false thread amount 1
    ===============main false
    main after create thread A Tue Oct 16 17:17:30 CST 2018 false thread amount 2
    ===============main false
    ===============Thread-0 true
    main after create thread B Tue Oct 16 17:17:33 CST 2018 false thread amount 3
    ===============main false
    ===============Thread-0 true
    ===============Thread-1 false
    main Exit: Tue Oct 16 17:17:33 CST 2018 false thread amount 3
    ===============main false
    ===============Thread-0 true
    ===============Thread-1 false
    Thread-0 Tue Oct 16 17:17:36 CST 2018 true thread amount 3
    ===============Thread-0 true // 这一行日志,说明他是守护线程,但是下面却没有了他的名字。因为他不是死循环,所以提前退出了?
    ===============Thread-1 false
    ===============DestroyJavaVM false
    Thread-1 before Counter:1 Tue Oct 16 17:17:36 CST 2018 false thread amount 2
    Thread-1 after Counter:2 Tue Oct 16 17:17:39 CST 2018 false thread amount 2
    ===============Thread-1 false
    ===============DestroyJavaVM false
    Thread-1 before Counter:3 Tue Oct 16 17:17:42 CST 2018 false thread amount 2
    Thread-1 after Counter:4 Tue Oct 16 17:17:45 CST 2018 false thread amount 2
    ===============Thread-1 false
    ===============DestroyJavaVM false

    结论:代码的逻辑让守护线程提前于用户线程消亡的情况下,守护线程并不会主动延长生命和用户线程一起消亡。但是,代码的逻辑让守护线程延迟于用户线程消亡的情况下,守护线程会提前和用户线程一起消亡。这样也可以理解,毕竟CPU资源那么金贵,既然守护线程提前与用户线程消亡,那他没有必要赖着占用CPU的资源,对吧?

  • 相关阅读:
    Java SE 疑难点记录
    重写(OverRide)与重载(OverlLoad),以及相对应的多态性
    Static 作用探讨
    Java SE作业:判断一个字符串是否是视频文件
    轨迹压缩之Douglas-Peucker算法之Java实现
    论主动思考与专注力——我的读研感悟
    西安电子科技大学2011级计算机科学与技术专业知识体系结构图
    Hadoop分布式平台概述
    Jest测试框架(未完)
    项目经验总结
  • 原文地址:https://www.cnblogs.com/babyha/p/9799432.html
Copyright © 2011-2022 走看看