0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

什么是守護(hù)線程?守護(hù)線程的底層原理和使用示例

CodeSheep ? 來源:飛天小牛肉 ? 2024-01-05 11:01 ? 次閱讀

大家好,今天這篇文章來梳理一下有關(guān)守護(hù)線程的相關(guān)問題,這也是之前曾經(jīng)有被問到過的面試題,在此之前我們先看一看守護(hù)線程的使用示例。

守護(hù)線程使用示例

我們先來看看下面這段代碼:

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

在上面的示例中,我們創(chuàng)建了一個守護(hù)線程daemonThread,并將其設(shè)置為守護(hù)線程。

主線程休眠一段時間后,主線程結(jié)束,程序退出,此時守護(hù)線程也會隨之結(jié)束。守護(hù)線程的DaemonTask會不斷地輸出消息,模擬后臺任務(wù)的執(zhí)行。

當(dāng)主線程結(jié)束后,你會注意到守護(hù)線程DaemonTask不再輸出消息,因?yàn)樗?JVM 中止了。

什么是守護(hù)線程

Java 把線程分成兩類:用戶線程(User Thread) + 守護(hù)線程(Daemon Thread)

守護(hù)線程的使用有以下要點(diǎn):

當(dāng)程序中所有的用戶線程執(zhí)行完畢之后,不管守護(hù)線程是否結(jié)束,系統(tǒng)都會自動退出(也就是說只要存在一個用戶線程在允許,守護(hù)線程就不會結(jié)束)

守護(hù)線程必須在start啟動前通過setDaemon()方法將狀態(tài)設(shè)置為 true,啟動后就不能進(jìn)行設(shè)置,否則報 InterruptedException 異常

守護(hù)線程存在被 JVM 強(qiáng)制終止的風(fēng)險,所以在守護(hù)線程中盡量不去訪問系統(tǒng)資源,例如打開文件等,因?yàn)樘摂M機(jī)退出時,守護(hù)線程沒有任何機(jī)會來關(guān)閉文件,這會導(dǎo)致數(shù)據(jù)丟失,所以守護(hù)線程適合執(zhí)行無需完整執(zhí)行的后臺任務(wù)。

守護(hù)線程中創(chuàng)建的線程也是守護(hù)線程

JVM 進(jìn)程中的 GC 線程就是一個守護(hù)線程,這樣設(shè)計(jì)目的很明確,當(dāng)你所有的程序都執(zhí)行完畢了,留著這個 GC 線程就沒有任何意義了。反過來可以設(shè)想,如果把 GC 線程設(shè)計(jì)成非守護(hù)線程,當(dāng)你明確你的程序都執(zhí)行完畢了,但是就是不自動退出豈不是很奇怪?

守護(hù)線程的底層原理

守護(hù)線程底層原理是啥?為什么用戶線程結(jié)束守護(hù)線程就能自動退出?(相信很多很多小伙伴遇到這個題都會直接懵,屬于低頻但重點(diǎn)的考點(diǎn))

我們看下 JVM 源碼thread.cpp文件,這里是實(shí)現(xiàn)線程的代碼。可以盲猜有一段代碼監(jiān)測著當(dāng)前非守護(hù)線程的數(shù)量,不然怎么知道現(xiàn)在只剩下守護(hù)線程呢?很有可能是在移除線程的方法里面,跟著這個思路,我們看看該文件的remove()方法。代碼如下

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

我在里面加了一些注釋,可以發(fā)現(xiàn),果然是我們想的那樣,里面有_number_of_non_daemon_threads記錄著非守護(hù)線程的數(shù)量,而且當(dāng)非守護(hù)線程數(shù)為 1 時,就會喚醒在destory_vm()方法里面等待的線程,緊接著我們看看destory_vm()代碼,同樣是在thread.cpp文件下:

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

可以看到當(dāng)非守護(hù)線程數(shù)量大于 1 時,就一直等待,直到剩下一個非守護(hù)線程時,就會在線程執(zhí)行完后,退出 JVM。

這時候又有一個點(diǎn)需要搞清楚,就是什么時候調(diào)用的destroy_vm()方法呢?還是通過查看代碼以及注釋,發(fā)現(xiàn)是在main()方法執(zhí)行完成后觸發(fā)的。

在java.c文件的JavaMain()方法里面,最后執(zhí)行完調(diào)用了LEAVE()方法,該方法調(diào)用了(*vm)->DestroyJavaVM(vm);來觸發(fā) JVM 退出,最終調(diào)用destroy_vm()方法。

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

總結(jié)下就是:Java 程序在 main 線程執(zhí)行退出時,會觸發(fā)執(zhí)行 JVM 退出操作(destroy_vm()方法),但是該方法會等待所有非守護(hù)線程(用戶線程)都執(zhí)行完,具體原理是使用變量_number_of_non_daemon_threads統(tǒng)計(jì)非守護(hù)線程的數(shù)量,這個變量在新增線程和刪除線程時會做增減操作。

另外衍生一點(diǎn)就是:當(dāng) JVM 退出時,所有還存在的守護(hù)線程會被拋棄,既不會執(zhí)行 finally 部分代碼,也不會 catch 異常。這個很明顯,JVM 都退出了,守護(hù)線程也就不能獨(dú)自存在了。

好了,以上就是今天的內(nèi)容分享,感謝大家的收看,我們下篇見。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2952

    瀏覽量

    104479
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4722

    瀏覽量

    68231
  • JVM
    JVM
    +關(guān)注

    關(guān)注

    0

    文章

    157

    瀏覽量

    12197
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    503

    瀏覽量

    19636

原文標(biāo)題:京東一面:守護(hù)線程如何實(shí)現(xiàn)的?

文章出處:【微信號:CodeSheep,微信公眾號:CodeSheep】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    Linux守護(hù)進(jìn)程

    這里將上一個示例程序用syslog服務(wù)進(jìn)行重寫,其中有區(qū)別的地方用加粗的字體表示,源代碼如下: /* syslog_daemon.c利用syslog服務(wù)的守護(hù)進(jìn)程實(shí)例 */ #include
    發(fā)表于 08-22 09:17

    Linux多線程線程間同步

    、是否為守護(hù)進(jìn)程等??梢允褂肗ULL來使用默認(rèn)值,通常情況下我們都是使用默認(rèn)值。void *(*func) (void *):函數(shù)指針func,指定當(dāng)新的線程創(chuàng)建之后,將執(zhí)行的函數(shù)。void *arg
    發(fā)表于 12-08 14:14

    Java守護(hù)線程和本地線程的區(qū)別

    java中的線程分為兩種:守護(hù)線程(Daemon)和用戶線程(User)。
    發(fā)表于 08-07 08:10

    Linux守護(hù)進(jìn)程詳解

    分享到:標(biāo)簽:進(jìn)程控制 Linux 守護(hù)進(jìn)程 子進(jìn)程 7.3 Linux守護(hù)進(jìn)程 7.3.1 守護(hù)進(jìn)程概述 守護(hù)進(jìn)程,也就是通常所說的Daemon進(jìn)程,是Linux中的后臺服務(wù)進(jìn)程。它
    發(fā)表于 10-18 14:24 ?0次下載
    Linux<b class='flag-5'>守護(hù)</b>進(jìn)程詳解

    線程編程之Linux線程編程

    9.2 Linux線程編程 9.2.1 線程基本編程 這里要講的線程相關(guān)操作都是用戶空間中的線程的操作。在Linux中,一般pthread線程
    發(fā)表于 10-18 15:55 ?3次下載

    線程好還是單線程好?單線程和多線程的區(qū)別 優(yōu)缺點(diǎn)分析

    摘要:如今單線程與多線程已經(jīng)得到普遍運(yùn)用,那么到底多線程好還是單線程好呢?單線程和多線程的區(qū)別又
    發(fā)表于 12-08 09:33 ?8.1w次閱讀

    Jvm工作原理學(xué)習(xí)筆記

    [] args)函數(shù)的class都可以作為JVM實(shí)例運(yùn)行的起點(diǎn) b) 運(yùn)行。main()作為該程序初始線程的起點(diǎn),任何其他線程均由該線程啟動。JVM內(nèi)部有兩種線程
    發(fā)表于 04-03 11:03 ?5次下載

    C#多線程技術(shù)

    C#和.NET類庫為開發(fā)多線程應(yīng)用程序提供了很方便的支持,本章首先簡要介紹.NET類庫中的Thread類及各種線程支持,再通過示例說明線程使用中需要掌握的規(guī)則,最后論述
    發(fā)表于 04-23 11:32 ?15次下載

    華為P30系列的芯片級守護(hù)

    芯片級守護(hù) 華為P30系列如何從底層保證通信安全?
    的頭像 發(fā)表于 08-28 11:18 ?4209次閱讀

    Linux的C編程中多線程如何終止某個線程示例與要點(diǎn)

    線程被另一個線程通過 pthread_cancel() 函數(shù)取消,這和通過kill() 發(fā)送 SIGKILL 信號類似。
    的頭像 發(fā)表于 04-27 13:41 ?3373次閱讀
    Linux的C編程中多<b class='flag-5'>線程</b>如何終止某個<b class='flag-5'>線程</b><b class='flag-5'>示例</b>與要點(diǎn)

    MFC多線程線程同步

    MFC中有兩類線程,分別稱之為工作者線程和用戶界面線程。二者的主要區(qū)別在于工作者線程沒有消息循環(huán),而用戶界面線程有自己的消息隊(duì)列和消息循環(huán)。
    發(fā)表于 06-01 17:03 ?0次下載

    為什么說線程是輕量級的概念呢?守護(hù)線程是指什么?

    當(dāng)多個線程同時搶多把鎖的時候就會出現(xiàn)死鎖的現(xiàn)象。其實(shí)遞歸鎖也不是一個很好地解決方案,死鎖現(xiàn)象的發(fā)生不是互斥鎖的原因,而是程序猿/媛的邏輯出現(xiàn)了問題。
    的頭像 發(fā)表于 08-19 10:39 ?2021次閱讀
    為什么說<b class='flag-5'>線程</b>是輕量級的概念呢?<b class='flag-5'>守護(hù)</b><b class='flag-5'>線程</b>是指什么?

    什么是線程線程池中線程實(shí)現(xiàn)復(fù)用的原理

    一般建議自定義線程工廠,構(gòu)建線程的時候設(shè)置線程的名稱,這樣就在查日志的時候就方便知道是哪個線程執(zhí)行的代碼。
    發(fā)表于 01-29 13:44 ?1690次閱讀

    線程線程

    線程池通常用于服務(wù)器應(yīng)用程序。 每個傳入請求都將分配給線程池中的一個線程,因此可以異步處理請求,而不會占用主線程,也不會延遲后續(xù)請求的處理
    的頭像 發(fā)表于 02-28 09:53 ?742次閱讀
    多<b class='flag-5'>線程</b>之<b class='flag-5'>線程</b>池

    線程池的線程怎么釋放

    線程分組看,pool名開頭線程占616條,而且waiting狀態(tài)也是616條,這個點(diǎn)就非??梢闪耍覕喽ň褪沁@個pool開頭線程池導(dǎo)致的問題。我們先排查為何這個線程池中會有600+的
    發(fā)表于 07-31 10:49 ?2206次閱讀
    <b class='flag-5'>線程</b>池的<b class='flag-5'>線程</b>怎么釋放