写在开头

面试官:小伙子请聊一聊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。如下图:

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

【源码解析1】

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

总结

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

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

结尾彩蛋

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

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

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

  1. Java守护线程

    最近的项目使用的是dubbo.Web工程发布在Tomcat上,会作为消费者调用其他的dubbo微服务.但是最近发现一个问题,在使用shutdown命令关闭tomcat的时候,Tomcat并没有真正关闭 ...

  2. 白话JAVA守护线程

    OneCoder(苦逼Coder)原创,转载请务必注明出处: http://www.coderli.com/archives/daemon-thread-plain-words/ 关于“白话”:偶然想 ...

  3. 转:JAVA守护线程

    原文地址:https://www.cnblogs.com/wxgblogs/p/5417503.html 详细内容看原文~  ,写的挺好的 在Java中有两类线程:User Thread(用户线程). ...

  4. Java 守护线程概述

    原文出处: 朱小厮 Java的线程分为两种:User Thread(用户线程).DaemonThread(守护线程). 只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作:只有当最 ...

  5. JAVA - 守护线程(Daemon Thread)

    转载自:http://www.cnblogs.com/luochengor/archive/2011/08/11/2134818.html 在Java中有两类线程:用户线程 (User Thread) ...

  6. java守护线程。

    java的守护线程:具体定义我也不太清楚,百度和谷歌了看的也不是很明白,但是啊,下边有给出一个例子自己领悟吧. 一.计时器的Timer声明时是否声明为守护线程对计时器的影响. /** * */ pac ...

  7. java 守护线程整理

    java中finally语句不走的可能存在system.exit(0)与守护线程 线程sleep采用TimeUnit类 设定线程的名字thread.getcurrentThread().setName ...

  8. Java 守护线程(Daemon) 例子

    当我们在Java中创建一个线程,缺省状态下它是一个User线程,如果该线程运行,JVM不会终结该程序.当一个线被标记为守护线程,JVM不会等待其结束,只要所有用户(User)线程都结束,JVM将终结程 ...

  9. 从 JVM 视角看看 Java 守护线程

    Java 多线程系列第 7 篇. 这篇我们来讲讲线程的另一个特性:守护线程 or 用户线程? 我们先来看看 Thread.setDaemon() 方法的注释,如下所示. Marks this thre ...

  10. java守护线程的理解

    package daemonThread; /*setDaemon(true)方法将线程设置为守护线程,线程的Daemon默认值为false * 只要当前JVM实例中存在任何一个非守护线程没有结束,守 ...

随机推荐

  1. py 学习(c++ to py)

    py1: print 2024-01-27 23:18:57 星期六 #这里是注释 # py1 : 基础print总结 ''' aaa 有时候也用三个单引号当注释 但其实是字符串 交互式会输出 ''' ...

  2. dropzone基本使用

    dropzone是一个实现拖拽上传文件的一个插件. 生成拖拽区域 1 <div style="width: 1078px;margin: 0 auto;border: 2px ligh ...

  3. How to 充分利用你的服务器

    服务器高性能计算指南 本文处于preview阶段,内容并不完全严谨,如有错误敬请原谅,适当参考. 目录 服务器高性能计算指南 什么样的计算适合当前服务器? 从CPU架构入手 两个CPU带来的影响 那么 ...

  4. blazor maui hybrid app显示本地图片

    啊... ... 一通操作下来感觉就是两个字 折磨 跨平台有跨平台的好处 但框架本身支持的有限 很多东西做起来很曲折 哎 这里总结一下笔者为了折腾本地图片显示的尝试 为什么要做本地图片展示呢 如果是做 ...

  5. Linux shell 判断变量是否包含某个字符串的几种方法

    方法一:利用grep查找 strA="long string" strB="string" result=$(echo $strA | grep "$ ...

  6. Codeforces Round #847 (Div. 3) A-G

    比赛链接 A 题意 判断输入字符串与 \(\pi\) 的最长前缀匹配,不超过 \(30\) 位. 题解 知识点:模拟. 抄样例最后一个 \(30\) 都正确的,直接匹配. 时间复杂度 \(O(1)\) ...

  7. MySQL基础之DCL语句

    DCL(Data Control Language)语句:数据控制语句. 用途:控制数据库.表.字段.用户的访问权限和安全级别. 常用关键字:grant.revoke等 一般用于管理数据库和用户的权限 ...

  8. Git 分支与合并

    1.  Git 对象 Git 的核心部分是一个简单的键值对数据库.可以向 Git 仓库中插入任意类型的内容,它会返回一个唯一的键,通过该键可以在任意时刻再次取回该内容. 所有内容均以树对象和数据对象的 ...

  9. Swoole从入门到入土(2)——TCP服务器[初步接触]

    我们知道Swoole弥补了PHP没办法实现长连接的短板,在接下来的话题中,我们会从TCP服务器.HTTP服务器.WebSocket服务器.协程.管道.中间件等话题,一个个进行讨论. 1.开篇 我们以S ...

  10. bootstrap响应式网页布局

    bootstrap可以说是没有布局和审美概念的后端狗的福利.使用它的栅格系统可以轻松的对网页进行布局,而且可以做到响应式的布局.看起来很酷,接下来我就会总结自己在开发博客系统中用到的知识点及实战案例给 ...