大家好,今天這篇文章來梳理一下有關(guān)守護(hù)線程的相關(guān)問題,這也是之前曾經(jīng)有被問到過的面試題,在此之前我們先看一看守護(hù)線程的使用示例。
守護(hù)線程使用示例
我們先來看看下面這段代碼:
在上面的示例中,我們創(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()方法。代碼如下
我在里面加了一些注釋,可以發(fā)現(xiàn),果然是我們想的那樣,里面有_number_of_non_daemon_threads記錄著非守護(hù)線程的數(shù)量,而且當(dāng)非守護(hù)線程數(shù)為 1 時,就會喚醒在destory_vm()方法里面等待的線程,緊接著我們看看destory_vm()代碼,同樣是在thread.cpp文件下:
可以看到當(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()方法。
總結(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)容分享,感謝大家的收看,我們下篇見。
審核編輯:湯梓紅
-
JAVA
+關(guān)注
關(guān)注
19文章
2952瀏覽量
104479 -
代碼
+關(guān)注
關(guān)注
30文章
4722瀏覽量
68231 -
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)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論