首页 > 编程语言 >面试准备不充分,被Java守护线程干懵了,面试官主打一个东西没用但你得会

面试准备不充分,被Java守护线程干懵了,面试官主打一个东西没用但你得会

时间:2024-03-09 16:22:56浏览次数:37  
标签:面试官 优先级 用户 线程 Java public 守护

写在开头

面试官:小伙子请聊一聊Java中的精灵线程?
我:什么?精灵线程?啥时候精灵线程?
面试官:精灵线程没听过?那守护线程呢?
我:守护线程知道,就是为普通线程服务的线程嘛。
面试官:没了?守护线程的特点,怎么使用,需要注意啥,Java中经典的守护线程都有啥?
我:不知道。。。
这的天,面试一个10K的工作,上来先整个精灵线程,直接把人整蒙了,难道提及Java多线程的时候,问的不应该是线程、线程池、并发冲突解决方案、如何加锁,以及各种锁的知识点吗?上来整个偏门的守护线程,这是出心的不想要啊。

何为守护线程

上面这段内容是在牛客上看到的,说实话这位面试官问的这内容确实主要一个:东西没用,但你得知道!可如果说他问的真是离谱吗?也算不上,精灵线程我们很少听到,但守护线程我们在学习Java线程的时候肯定有所耳闻!那么今天我们就一起来小酌一下这个 守护线程

Java中的线程分为2种:用户线程守护线程

用户线程又叫普通线程,是我们驱动业务逻辑运转的核心;而守护线程,顾名思义,是守护用户线程的一种线程,运行在后台提供通用服务,因此也叫后台线程或者精灵线程。

守护线程的使用场景

那在Java中这个守护线程都有什么实际用处,或者说应用场景呢?

  1. GC垃圾回收线程:这是JVM中非常经典的一个守护线程,它始终以低级别状态运行,用于实时监控和管理系统中的可回收资源,一旦我们的系统没有任何运行的用户线程时,程序也就不会再产生垃圾,这时,无事可做的垃圾回收线程会自动结束。
  2. 应用指标统计:部分服务可以通过守护线程来采取应用指标,服务结束则停止采集。

怎么设置守护线程

那我们在代码中,如何将一个线程设置为守护线程呢?咱们可以通过在 start 线程之前调用线程的 setDaemon(true) 方法,将一个线程设置为守护线程,来看一下下面的这个demo。

【代码实例1】

public class Test {
    public static void main(String[] args) {
        Thread thread1 = new Thread("守护线程"){
            @Override
            public void run() {
                int i = 0;
                while (i <= 4){
                    i++;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
                super.run();
            }
        };
        Thread thread2 = new Thread("用户线程"){
            @Override
            public void run() {
                int i = 0;
                while (i < 2){
                    i++;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
                super.run();
            }
        };
        //setDaemon, 不设置则默认false
        thread1.setDaemon(true);//设置thread1为守护线程
        thread2.setDaemon(false);//设置thread2为普通线程
        thread1.start();
        thread2.start();
    }
}

输出:

守护线程:1
用户线程:1
用户线程:2
守护线程:2

这段测试代码中,我们通过thread1.setDaemon(true)将线程1设置成了一个守护线程(false为普通线程),用户线程的循环次数为2,用户线程的循环次数为4,但当程序中的用户线程运行完之后,守护线程并没有继续向下循环,而是随着用户线程的结束而自我终止了。

守护线程的优先级

看到网上很多博文提到了守护线程的优先级问题,都说守护线程的优先级比较低,那我们通过一段测试用例看一下真实情况。

【代码实例2】

public class Test {
    public static void main(String[] args) {
        Thread thread1 = new Thread("守护线程"){
            @Override
            public void run() {
                int i = 0;
                while (i <= 4){
                    i++;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+i+"-优先级:" +Thread.currentThread().getPriority());
                }
                super.run();
            }
        };
        Thread thread2 = new Thread("用户线程"){
            @Override
            public void run() {
                int i = 0;
                while (i < 2){
                    i++;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+i+"-优先级:" +Thread.currentThread().getPriority());
                }
                super.run();
            }
        };

        //setDaemon, 不设置则默认false
        thread1.setDaemon(true);//设置thread1为守护线程
        thread2.setDaemon(false);//设置thread2为普通线程

        thread1.start();
        thread2.start();

        for (int i = 0; i <5 ; i++) {
            System.out.println("主线程:"+i+"-优先级:" +Thread.currentThread().getPriority());
        }
    }
}

输出:

主线程:0-优先级:5
主线程:1-优先级:5
主线程:2-优先级:5
主线程:3-优先级:5
主线程:4-优先级:5
用户线程:1-优先级:5
守护线程:1-优先级:5
用户线程:2-优先级:5
守护线程:2-优先级:5

这个测试结果是不是出乎意料?无论是主线程还是普通的用户线程,又或者说守护线程,他们的优先级都是5,优先级竟然都一样!

我们知道所谓的线程就是CPU 调度和分派的基本单位,根据优先级不同,来决定获取CPU时间片的先后顺序,因为主线程启动时,其他线程还没有启动,所以这时候它最先获得CPU调度权限;

又因为其他线程存在休眠时间,这个时间段上足够主线程执行完毕。主线程执行完后,用户线程和守护线程互相抢占CPU资源,交错执行,直至程序中没有普通线程为止!若没有休眠时间,且循环次数足够多时,我们可以看到主线程、守护线程、用户线程都竞争CPU时间片,呈现交错执行的结果!

注意事项

在设置线程为守护线程的时候要注意一个事情,那就是当 start(); 放到 setDaemon(true); 之前,程序抛出IllegalThreadStateException。如下图:
image

原因是 setDaemon(true)源码中,有一个isAlive()的判断,判断当前线程的状态是否为活跃线程,若是则抛出异常,我们不能修改一个正在运行中的线程!

【源码解析1】

  public final void setDaemon(boolean on) {
        checkAccess();
        //线程已经启动后,不可修改,否则抛出非法线程状态异常
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }

总结

OK,写到这里,关于守护线程的内容就讲完了,我们从什么是守护线程,守护线程的使用场景,优先级,注意事项等方面,进行了全面的介绍。

其实说实话,在我们日后工作中,很少直接使用上守护线程,所以它看似没那么重要,但在很多Java多线程相关的书籍中绝对都有提及,很多小伙伴在学习的过程中认为这个点不重要,也就相当然的忽略了,但遇到变态的面试官,专门挑拣一些偏僻的知识点考你时,难免陷入尴尬,所以希望借助这个考题,大家能够在日后更细心的学习哈。

结尾彩蛋

如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

image

如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

image

标签:面试官,优先级,用户,线程,Java,public,守护
From: https://www.cnblogs.com/JavaBuild/p/18062883

相关文章

  • java List<HashMap<String,Object>> 遍历修改
    List<HashMap<String,Object>>DataSource;inti=0;for(Map<String,Object>item:DataSource){for(Stringk:item.keySet()){if(k.equals("input_date")){//此句为判断条件可去掉Objectb=item.get(k);......
  • java.util.ConcurrentModificationException
    用for循环遍历删除不会报错但是结果未达到预期解决方法......
  • Java多线程
    1.java线程实现/创建的方式(主要是两种)继承Thread类本质是通过实现Runnable接口的一个实例,代表一个线程的实例publicclassMyThreadextendsThread{publicvoidrun(){System.out.println("run()")}}MyThreadthread=newMyThread();thread.st......
  • Java8方法引用简化Lambda
    静态方法引用importlombok.AllArgsConstructor;importlombok.Data;importjava.lang.reflect.Array;importjava.util.Arrays;importjava.util.Comparator;importjava.util.zip.DeflaterOutputStream;/***@authorPickle*@versionV1.0*@date2024/3/823:3......
  • Java学习笔记——第十天
    面向对象高级(一)staticstatic是一个关键字,义为静态,可以修饰成员变量和成员方法。static修饰成员变量成员变量的分类类变量(静态成员变量):有static修饰的成员变量,它们属于类,在计算机里只有一份,会被类的全部对象共享。实例变量(对象成员变量):无static修饰的成员变量,属于每个对象,每......
  • Java入门(Java诞生、特性、版本、开发环境搭建)
    Java入门1.Java帝国的诞生—一场旷日持久的战争(1)1972年C语言诞生:贴近硬件,运行极快,效率极高;应用于:操作系统、编译器、数据库、网路系统等;难点:指针和内存管理;(2)1982年C++诞生:面向对象;兼容C语言;应用于:图像领域、游戏等;(3)Java帝国的诞生:1995年Java诞生:网页简单而粗糙......
  • 01.基于javaEE_大学生就业信息管理系统源码
    基于javaEE_大学生就业信息管理系统:本系统分系统管理员,教师用户,企业用户和毕业生用户4个用户角色。**系统管理员主要功能有系别管理、专业管理、老师管理员管理、站内新闻管理、企业用户管理、岗位管理、文档管理、公告管理、留言管理、就业查询统计(包括就业情况查询,区域分布统......
  • Java蓝桥杯题目——1264排个序
    题目 思路:1、输入数据2、用冒泡排序将数组(下标为pj的)部分升序,3、判断是否有前一个元素大于后一个元素(降序),有则返回false注意:(1)数组p元素的取值不能大于数组a的长度,因为p元素是a的下标(2)数组下标越界问题,使用i<a.length判断(3)并非所有元素都要降序才返回false,只要有前一个元......
  • Java ArrayList 与 LinkedList 的灵活选择
    JavaArrayListJavaArrayList类是一个可变大小的数组,位于java.util包中。创建ArrayListimportjava.util.ArrayList;ArrayList<String>cars=newArrayList<String>();//创建一个ArrayList对象添加元素cars.add("Volvo");cars.add("BMW");cars.add(......
  • java实现浏览器下载附件时文件名中文乱码解决方案
    方案一:URLEncoder解决IE和谷歌浏览器的附件中文名问题。如果客户端浏览器是IE浏览器或者是谷歌浏览器。我们需要使用URLEncoder类先对中文名进行UTF-8的编码操作。因为IE浏览器和谷歌浏览器收到含有编码后的字符串后会以UTF-8字符集进行解码显示。//把中文名......