来聊聊守护线程
写在文章前面
近期和朋友交流时谈及守护线程,遂整理一篇关于守护线程的文章,让读者会守护线程有更进一步的认识,本文整体内容如下:
你好,我叫sharkchili,目前还是在一线奋斗的Java开发,经历过很多有意思的项目,也写过很多有意思的文章,是CSDN Java领域的博客专家,也是Java Guide的维护者之一,非常欢迎你关注我的公众号:写代码的SharkChili,这里面会有笔者精心挑选的并发、JVM、MySQL数据库专栏,也有笔者日常分享的硬核技术小文。
关于守护线程的一些介绍
很多人对守护线程都不陌生,对于守护线程大部分读者都停留在JDK官方文档所介绍的概念:
The Java Virtual Machine exits when the only threads running are all daemon threads.
文档的意思是当JVM中不存在任何一个正在运行的非守护线程时,JVM进程会直接退出。
读起来很拗口对不对,没关系,本文就会基于几个代码示例,让你更深层次的理解守护线程。在此之前,读者不妨自测一下,下面这几道面试题:
- 守护线程和普通线程有什么区别?
- 守护线程默认优先级是多少?
- 若父线程为守护线程,在其内部创建一个普通线程,父线程停止,子线程是否也会停止呢?
- 如何创建守护线程池?
- 守护线程使用有哪些注意事项?
基于示例了解守护线程
守护线程和普通线程的区别
要了解区别就先来了解一下两者的使用,非守护线程,也就我们日常创建的普通线程,可以看到这段代码创建了一个普通线程,在无限循环的定时输出内容,而主线程仅仅是输出一段文字后就不做任何动作了。
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (true) {
log.info("普通线程执行了......");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
log.info("主线程运行结束");
}
对应的输出结果如下,可以看到,即使主线程停止运行了,而非守护线程也仍然会在运行,也就是JDK官方文档的字面含义,普通线程不停止,JVM就不停止运行:
12:44:57.022 [Thread-0] INFO com.sharkChili.webTemplate.Main - 普通线程执行了......
12:44:57.022 [main] INFO com.sharkChili.webTemplate.Main - 主线程运行结束
12:45:02.031 [Thread-0] INFO com.sharkChili.webTemplate.Main - 普通线程执行了......
基于上述代码,用setDaemon(true)将该线程设置为守护线程:
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (true) {
log.info("守护线程执行了......");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//设置当前线程为守护线程
t.setDaemon(true);
t.start();
log.info("主线程运行结束");
}
输出结果如下,可以看到随着主线程的消亡,守护线程也会随之停止,不再运行,自此我相信读者可以理解JDK官方文档所说的那句话了,只要有一个普通线程在,JVM就不会退出,只要所有普通线程停止工作,JVM自动退出,守护线程也会自动结束。
12:44:23.239 [Thread-0] INFO com.sharkChili.webTemplate.Main - 守护线程执行了......
12:44:23.239 [main] INFO com.sharkChili.webTemplate.Main - 主线程运行结束
守护线程和普通线程优先级的区别
我们可以通过getPriority方法查看两者的区别:
public static void main(String[] args) {
Thread t = new Thread(() -> {
log.info("守护线程优先级:{}", Thread.currentThread().getPriority());
});
//设置当前线程为守护线程
t.setDaemon(true);
t.start();
log.info("主线程运行结束,当前线程运行优先级:{}", Thread.currentThread().getPriority());
}
从输出结果来看,两者的优先级是一样的,都为5:
12:54:36.344 [main] INFO com.sharkChili.webTemplate.Main - 主线程运行结束,当前线程运行优先级:5
12:54:36.344 [Thread-0] INFO com.sharkChili.webTemplate.Main - 守护线程优先级:5
父守护线程问题
我们创建了一个守护线程,在其runnable实现中创建一个子线程:
public static void main(String[] args) {
Thread parentThread = new Thread(() -> {
Thread childThread = new Thread(() -> {
while (true) {
log.info("子线程运行中,是否为守护线程:{}",Thread.currentThread().isDaemon());
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
childThread.start();
log.info("parentThread守护线程运行中");
});
//设置当前线程为守护线程
parentThread.setDaemon(true);
parentThread.start();
log.info("主线程运行结束");
}
从输出结果来看,父线程为守护线程时,其内部创建的子线程也为守护线程,所以随着父线程的销毁,子线程也会同步销毁。
00:05:56.869 [Thread-1] INFO com.sharkChili.webTemplate.Main - 子线程运行中,是否为守护线程:true
00:05:56.869 [main] INFO com.sharkChili.webTemplate.Main - 主线程运行结束
00:05:56.869 [Thread-0] INFO com.sharkChili.webTemplate.Main - parentThread守护线程运行中
守护线程池的创建
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(10, ThreadFactoryBuilder.create()
.setNamePrefix("worker-")
.setDaemon(true)
.build());
threadPool.execute(()->{
while (true){
try {
log.info("守护线程运行了");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
log.info("主线程退出");
}
小结
守护线程的使用场景
因为守护线程拥有自动结束自己生命周期的特性,当JVM中没有一个普通线程运行时,JVM会退出,即所有守护线程会自动停止,所以守护线程的使用场景可以有以下几种:
- 垃圾回收线程就是典型的守护线程,在后台进行垃圾对象回收的工作。
- 非核心业务工作可交由守护线程,例如:各类信息统计、服务监控等,一旦进程结束运行则这些守护线程停止工作。
守护线程注意事项
- 复杂计算、资源回收这种不建议使用守护线程。
- setDaemon要在start方法前面,否者该设置会不生效。
我是sharkchili,CSDN Java 领域博客专家,开源项目—JavaGuide contributor,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号:
写代码的SharkChili,同时我的公众号也有我精心整理的并发编程、JVM、MySQL数据库个人专栏导航。
参考文章
Java 多线程之守护 (Daemon) 线程:https://blog.csdn.net/qq_33479841/article/details/121950775
JAVA多线程基础篇–守护线程(Daemon Thread):https://www.exception.site/java-concurrency/java-concurrency-daemon-thread
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!