前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我麻了,京东一面:守护线程如何实现的?

我麻了,京东一面:守护线程如何实现的?

作者头像
飞天小牛肉
发布2023-08-26 14:46:16
1690
发布2023-08-26 14:46:16
举报
文章被收录于专栏:飞天小牛肉飞天小牛肉

守护线程使用示例

看下面这段代码:

在上面的示例中,我们创建了一个守护线程 daemonThread,并将其设置为守护线程。主线程休眠一段时间后,主线程结束,程序退出,此时守护线程也会随之结束。守护线程的 DaemonTask 会不断地输出消息,模拟后台任务的执行。当主线程结束后,你会注意到守护线程 DaemonTask 不再输出消息,因为它被 JVM 中止了。

什么是守护线程

Java 把线程分成两类:用户线程(User Thread) + 守护线程(Daemon Thread)

守护线程的使用有以下要点:

  • 当程序中所有的用户线程执行完毕之后,不管守护线程是否结束,系统都会自动退出(也就是说只要存在一个用户线程在允许,守护线程就不会结束)
  • 守护线程必须在 start 启动前通过 setDaemon() 方法将状态设置为 true,启动后就不能进行设置,否则报 InterruptedException 异常
  • 守护线程存在被 JVM 强制终止的风险,所以在守护线程中尽量不去访问系统资源,例如打开文件等,因为虚拟机退出时,守护线程没有任何机会来关闭文件,这会导致数据丢失,所以守护线程适合执行无需完整执行的后台任务。
  • 守护线程中创建的线程也是守护线程

JVM 进程中的 GC 线程就是一个守护线程,这样设计目的很明确,当你所有的程序都执行完毕了,留着这个 GC 线程就没有任何意义了。反过来可以设想,如果把 GC 线程设计成非守护线程,当你明确你的程序都执行完毕了,但是就是不自动退出岂不是很奇怪?

守护线程的底层原理

守护线程底层原理是啥?为什么用户线程结束守护线程就能自动退出?(相信很多很多小伙伴遇到这个题都会直接懵,属于低频但重点的考点)

我们看下 JVM 源码 thread.cpp 文件,这里是实现线程的代码。可以盲猜有一段代码监测着当前非守护线程的数量,不然怎么知道现在只剩下守护线程呢?很有可能是在移除线程的方法里面,跟着这个思路,我们看看该文件的 remove() 方法。代码如下

我在里面加了一些注释,可以发现,果然是我们想的那样,里面有 _number_of_non_daemon_threads 记录着非守护线程的数量,而且当非守护线程数为 1 时,就会唤醒在 destory_vm() 方法里面等待的线程,紧接着我们看看 destory_vm() 代码,同样是在 thread.cpp 文件下:

可以看到当非守护线程数量大于 1 时,就一直等待,直到剩下一个非守护线程时,就会在线程执行完后,退出 JVM。这时候又有一个点需要搞清楚,就是什么时候调用的 destroy_vm() 方法呢?还是通过查看代码以及注释,发现是在 main() 方法执行完成后触发的。

java.c 文件的 JavaMain() 方法里面,最后执行完调用了 LEAVE() 方法,该方法调用了 (*vm)->DestroyJavaVM(vm); 来触发 JVM 退出,最终调用 destroy_vm() 方法。

总结下就是:Java 程序在 main 线程执行退出时,会触发执行 JVM 退出操作( destroy_vm() 方法),但是该方法会等待所有非守护线程(用户线程)都执行完,具体原理是使用变量 _number_of_non_daemon_threads 统计非守护线程的数量,这个变量在新增线程和删除线程时会做增减操作。

另外衍生一点就是:当 JVM 退出时,所有还存在的守护线程会被抛弃,既不会执行 finally 部分代码,也不会 catch 异常。这个很明显,JVM 都退出了,守护线程还能独自存在?

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 飞天小牛肉 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是守护线程
  • 守护线程的底层原理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档