面试官:小伙子请聊一聊Java中的精灵线程?
我:什么?精灵线程?啥时候精灵线程?
面试官:精灵线程没听过?那守护线程呢?
我:守护线程知道,就是为普通线程服务的线程嘛。
面试官:没了?守护线程的特点,怎么使用,需要注意啥,Java中经典的守护线程都有啥?
我:不知道。。。
这的天,面试一个10K的工作,上来先整个精灵线程,直接把人整蒙了,难道提及Java多线程的时候,问的不应该是线程、线程池、并发冲突解决方案、如何加锁,以及各种锁的知识点吗?上来整个偏门的守护线程,这是出心的不想要啊。
何为守护线程
上面这段内容是在牛客上看到的,说实话这位面试官问的这内容确实主要一个:东西没用,但你得知道!可如果说他问的真是离谱吗?也算不上,精灵线程我们很少听到,但守护线程我们在学习Java线程的时候肯定有所耳闻!那么今天我们就一起来小酌一下这个 “ 守护线程 ”
Java中的线程分为2种:用户线程和守护线程
用户线程又叫普通线程,是我们驱动业务逻辑运转的核心;而守护线程,顾名思义,是守护用户线程的一种线程,运行在后台提供通用服务,因此也叫后台线程或者精灵线程。
守护线程的使用场景
那在Java中这个守护线程都有什么实际用处,或者说应用场景呢?
- GC垃圾回收线程:这是JVM中非常经典的一个守护线程,它始终以低级别状态运行,用于实时监控和管理系统中的可回收资源,一旦我们的系统没有任何运行的用户线程时,程序也就不会再产生垃圾,这时,无事可做的垃圾回收线程会自动结束。
- 应用指标统计:部分服务可以通过守护线程来采取应用指标,服务结束则停止采集。
怎么设置守护线程
那我们在代码中,如何将一个线程设置为守护线程呢?咱们可以通过在 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多线程相关的书籍中绝对都有提及,很多小伙伴在学习的过程中认为这个点不重要,也就相当然的忽略了,但遇到变态的面试官,专门挑拣一些偏僻的知识点考你时,难免陷入尴尬,所以希望借助这个考题,大家能够在日后更细心的学习哈。
结尾彩蛋
我是啊哈,一个工作十四年经验的Java程序员!
最近很多同学问我有没有java学习资料,我根据我从小白到架构师多年的学习经验整理出来了一份80W字面试解析文档、简历模板、学习路线图、java必看学习书籍 、 需要的小伙伴 可以关注我
公众号:“ 灰灰聊架构 ”, 回复暗号:“ 158”即可获取

被折叠的 条评论
为什么被折叠?



