0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么是守护线程?守护线程的底层原理和使用示例

CodeSheep 来源:飞天小牛肉 2024-01-05 11:01 次阅读

大家好,今天这篇文章来梳理一下有关守护线程的相关问题,这也是之前曾经有被问到过的面试题,在此之前我们先看一看守护线程的使用示例。

守护线程使用示例

我们先来看看下面这段代码:

5ef8c72a-ab66-11ee-8b88-92fbcf53809c.png

在上面的示例中,我们创建了一个守护线程daemonThread,并将其设置为守护线程。

主线程休眠一段时间后,主线程结束,程序退出,此时守护线程也会随之结束。守护线程的DaemonTask会不断地输出消息,vwin 后台任务的执行。

当主线程结束后,你会注意到守护线程DaemonTask不再输出消息,因为它被 JVM 中止了。

什么是守护线程

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

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

当程序中所有的用户线程执行完毕之后,不管守护线程是否结束,系统都会自动退出(也就是说只要存在一个用户线程在允许,守护线程就不会结束)

守护线程必须在start启动前通过setDaemon()方法将状态设置为 true,启动后就不能进行设置,否则报 InterruptedException 异常

守护线程存在被 JVM 强制终止的风险,所以在守护线程中尽量不去访问系统资源,例如打开文件等,因为虚拟机退出时,守护线程没有任何机会来关闭文件,这会导致数据丢失,所以守护线程适合执行无需完整执行的后台任务。

守护线程中创建的线程也是守护线程

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

守护线程的底层原理

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

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

5f164fd4-ab66-11ee-8b88-92fbcf53809c.png

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

5f3a45b0-ab66-11ee-8b88-92fbcf53809c.png

可以看到当非守护线程数量大于 1 时,就一直等待,直到剩下一个非守护线程时,就会在线程执行完后,退出 JVM。

这时候又有一个点需要搞清楚,就是什么时候调用的destroy_vm()方法呢?还是通过查看代码以及注释,发现是在main()方法执行完成后触发的。

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

5f4b2e8e-ab66-11ee-8b88-92fbcf53809c.png

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

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

好了,以上就是今天的内容分享,感谢大家的收看,我们下篇见。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表德赢Vwin官网 网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2934

    浏览量

    103901
  • 代码
    +关注

    关注

    30

    文章

    4642

    浏览量

    67648
  • JVM
    JVM
    +关注

    关注

    0

    文章

    155

    浏览量

    12166
  • 线程
    +关注

    关注

    0

    文章

    500

    浏览量

    19575

原文标题:京东一面:守护线程如何实现的?

文章出处:【微信号:CodeSheep,微信公众号:CodeSheep】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Linux守护进程

    这里将上一个 示例程序用syslog服务进行重写,其中有区别的地方用加粗的字体表示,源代码如下: /* syslog_daemon.c利用syslog服务的 守护进程实例 */ #include
    发表于08-22 09:17

    Linux多线程线程间同步

    、是否为 守护进程等。可以使用NULL来使用默认值,通常情况下我们都是使用默认值。void *(*func) (void *):函数指针func,指定当新的 线程创建之后,将执行的函数。void *arg
    发表于12-08 14:14

    Java守护线程和本地线程的区别

    java中的 线程分为两种: 守护 线程(Daemon)和用户 线程(User)。
    发表于08-07 08:10

    Linux守护进程详解

    分享到:标签:进程控制 Linux 守护进程 子进程 7.3 Linux 守护进程 7.3.1 守护进程概述 守护进程,也就是通常所说的Daemon进程,是Linux中的后台服务进程。它
    发表于10-18 14:24 0次下载
    Linux<b class='flag-5'>守护</b>进程详解

    线程编程之Linux线程编程

    9.2 Linux 线程编程 9.2.1 线程基本编程 这里要讲的 线程相关操作都是用户空间中的 线程的操作。在Linux中,一般pthread 线程
    发表于10-18 15:55 3次下载

    线程好还是单线程好?单线程和多线程的区别 优缺点分析

    摘要:如今单 线程与多 线程已经得到普遍运用,那么到底多 线程好还是单 线程好呢?单 线程和多 线程的区别又
    发表于12-08 09:33 8.1w次阅读

    Jvm工作原理学习笔记

    [] args)函数的class都可以作为JVM实例运行的起点 b) 运行。main()作为该程序初始 线程的起点,任何其他 线程均由该 线程启动。JVM内部有两种 线程
    发表于04-03 11:03 5次下载

    C#多线程技术

    C#和.NET类库为开发多 线程应用程序提供了很方便的支持,本章首先简要介绍.NET类库中的Thread类及各种 线程支持,再通过 示例说明 线程使用中需要掌握的规则,最后论述
    发表于04-23 11:32 14次下载

    华为P30系列的芯片级守护

    芯片级 守护华为P30系列如何从 底层保证通信安全?
    的头像 发表于08-28 11:18 4104次阅读

    MFC多线程线程同步

    MFC中有两类 线程,分别称之为工作者 线程和用户界面 线程。二者的主要区别在于工作者 线程没有消息循环,而用户界面 线程有自己的消息队列和消息循环。
    发表于06-01 17:03 0次下载

    为什么说线程是轻量级的概念呢?守护线程是指什么?

    当多个 线程同时抢多把锁的时候就会出现死锁的现象。其实递归锁也不是一个很好地解决方案,死锁现象的发生不是互斥锁的原因,而是程序猿/媛的逻辑出现了问题。
    的头像 发表于08-19 10:39 1887次阅读
    为什么说<b class='flag-5'>线程</b>是轻量级的概念呢?<b class='flag-5'>守护</b><b class='flag-5'>线程</b>是指什么?

    什么是线程线程池中线程实现复用的原理

    一般建议自定义 线程工厂,构建 线程的时候设置 线程的名称,这样就在查日志的时候就方便知道是哪个 线程执行的代码。
    发表于01-29 13:44 1534次阅读

    线程线程

    线程池通常用于服务器应用程序。 每个传入请求都将分配给 线程池中的一个 线程,因此可以异步处理请求,而不会占用主 线程,也不会延迟后续请求的处理
    的头像 发表于02-28 09:53 635次阅读
    多<b class='flag-5'>线程</b>之<b class='flag-5'>线程</b>池

    线程池的线程怎么释放

    线程分组看,pool名开头 线程占616条,而且waiting状态也是616条,这个点就非常可疑了,我断定就是这个pool开头 线程池导致的问题。我们先排查为何这个 线程池中会有600+的
    发表于07-31 10:49 1997次阅读
    <b class='flag-5'>线程</b>池的<b class='flag-5'>线程</b>怎么释放

    线程事务怎么回滚?一个简单示例演示多线程事务

    在spring中可以使用@Transactional注解去控制事务,使出现异常时会进行回滚,在多 线程中,这个注解则不会生效,如果主 线程需要先执行一些修改数据库的操作,当子 线程在进行处理出现异常时,主
    发表于08-09 12:22 572次阅读
    多<b class='flag-5'>线程</b>事务怎么回滚?一个简单<b class='flag-5'>示例</b>演示多<b class='flag-5'>线程</b>事务