大家好,今天這篇文章來梳理一下有關守護線程的相關問題,這也是之前曾經有被問到過的面試題,在此之前我們先看一看守護線程的使用示例。
守護線程使用示例
我們先來看看下面這段代碼:
在上面的示例中,我們創建了一個守護線程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 都退出了,守護線程也就不能獨自存在了。
好了,以上就是今天的內容分享,感謝大家的收看,我們下篇見。
審核編輯:湯梓紅
-
JAVA
+關注
關注
20文章
2982瀏覽量
106391 -
代碼
+關注
關注
30文章
4871瀏覽量
69909 -
JVM
+關注
關注
0文章
159瀏覽量
12444 -
線程
+關注
關注
0文章
507瀏覽量
19990
原文標題:京東一面:守護線程如何實現的?
文章出處:【微信號:CodeSheep,微信公眾號:CodeSheep】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
Linux守護進程
Linux多線程及線程間同步
多線程編程之Linux線程編程
多線程好還是單線程好?單線程和多線程的區別 優缺點分析
Jvm工作原理學習筆記
C#多線程技術
MFC多線程及線程同步
線程池的線程怎么釋放

多線程事務怎么回滾?一個簡單示例演示多線程事務

評論