大家好,今天這篇文章來(lái)梳理一下有關(guān)守護(hù)線(xiàn)程的相關(guān)問(wèn)題,這也是之前曾經(jīng)有被問(wèn)到過(guò)的面試題,在此之前我們先看一看守護(hù)線(xiàn)程的使用示例。
守護(hù)線(xiàn)程使用示例
我們先來(lái)看看下面這段代碼:
在上面的示例中,我們創(chuàng)建了一個(gè)守護(hù)線(xiàn)程daemonThread,并將其設(shè)置為守護(hù)線(xiàn)程。
主線(xiàn)程休眠一段時(shí)間后,主線(xiàn)程結(jié)束,程序退出,此時(shí)守護(hù)線(xiàn)程也會(huì)隨之結(jié)束。守護(hù)線(xiàn)程的DaemonTask會(huì)不斷地輸出消息,模擬后臺(tái)任務(wù)的執(zhí)行。
當(dāng)主線(xiàn)程結(jié)束后,你會(huì)注意到守護(hù)線(xiàn)程DaemonTask不再輸出消息,因?yàn)樗?JVM 中止了。
什么是守護(hù)線(xiàn)程
Java 把線(xiàn)程分成兩類(lèi):用戶(hù)線(xiàn)程(User Thread) + 守護(hù)線(xiàn)程(Daemon Thread)
守護(hù)線(xiàn)程的使用有以下要點(diǎn):
當(dāng)程序中所有的用戶(hù)線(xiàn)程執(zhí)行完畢之后,不管守護(hù)線(xiàn)程是否結(jié)束,系統(tǒng)都會(huì)自動(dòng)退出(也就是說(shuō)只要存在一個(gè)用戶(hù)線(xiàn)程在允許,守護(hù)線(xiàn)程就不會(huì)結(jié)束)
守護(hù)線(xiàn)程必須在start啟動(dòng)前通過(guò)setDaemon()方法將狀態(tài)設(shè)置為 true,啟動(dòng)后就不能進(jìn)行設(shè)置,否則報(bào) InterruptedException 異常
守護(hù)線(xiàn)程存在被 JVM 強(qiáng)制終止的風(fēng)險(xiǎn),所以在守護(hù)線(xiàn)程中盡量不去訪(fǎng)問(wèn)系統(tǒng)資源,例如打開(kāi)文件等,因?yàn)樘摂M機(jī)退出時(shí),守護(hù)線(xiàn)程沒(méi)有任何機(jī)會(huì)來(lái)關(guān)閉文件,這會(huì)導(dǎo)致數(shù)據(jù)丟失,所以守護(hù)線(xiàn)程適合執(zhí)行無(wú)需完整執(zhí)行的后臺(tái)任務(wù)。
守護(hù)線(xiàn)程中創(chuàng)建的線(xiàn)程也是守護(hù)線(xiàn)程
JVM 進(jìn)程中的 GC 線(xiàn)程就是一個(gè)守護(hù)線(xiàn)程,這樣設(shè)計(jì)目的很明確,當(dāng)你所有的程序都執(zhí)行完畢了,留著這個(gè) GC 線(xiàn)程就沒(méi)有任何意義了。反過(guò)來(lái)可以設(shè)想,如果把 GC 線(xiàn)程設(shè)計(jì)成非守護(hù)線(xiàn)程,當(dāng)你明確你的程序都執(zhí)行完畢了,但是就是不自動(dòng)退出豈不是很奇怪?
守護(hù)線(xiàn)程的底層原理
守護(hù)線(xiàn)程底層原理是啥?為什么用戶(hù)線(xiàn)程結(jié)束守護(hù)線(xiàn)程就能自動(dòng)退出?(相信很多很多小伙伴遇到這個(gè)題都會(huì)直接懵,屬于低頻但重點(diǎn)的考點(diǎn))
我們看下 JVM 源碼thread.cpp文件,這里是實(shí)現(xiàn)線(xiàn)程的代碼??梢悦げ掠幸欢未a監(jiān)測(cè)著當(dāng)前非守護(hù)線(xiàn)程的數(shù)量,不然怎么知道現(xiàn)在只剩下守護(hù)線(xiàn)程呢?很有可能是在移除線(xiàn)程的方法里面,跟著這個(gè)思路,我們看看該文件的remove()方法。代碼如下
我在里面加了一些注釋?zhuān)梢园l(fā)現(xiàn),果然是我們想的那樣,里面有_number_of_non_daemon_threads記錄著非守護(hù)線(xiàn)程的數(shù)量,而且當(dāng)非守護(hù)線(xiàn)程數(shù)為 1 時(shí),就會(huì)喚醒在destory_vm()方法里面等待的線(xiàn)程,緊接著我們看看destory_vm()代碼,同樣是在thread.cpp文件下:
可以看到當(dāng)非守護(hù)線(xiàn)程數(shù)量大于 1 時(shí),就一直等待,直到剩下一個(gè)非守護(hù)線(xiàn)程時(shí),就會(huì)在線(xiàn)程執(zhí)行完后,退出 JVM。
這時(shí)候又有一個(gè)點(diǎn)需要搞清楚,就是什么時(shí)候調(diào)用的destroy_vm()方法呢?還是通過(guò)查看代碼以及注釋?zhuān)l(fā)現(xiàn)是在main()方法執(zhí)行完成后觸發(fā)的。
在java.c文件的JavaMain()方法里面,最后執(zhí)行完調(diào)用了LEAVE()方法,該方法調(diào)用了(*vm)->DestroyJavaVM(vm);來(lái)觸發(fā) JVM 退出,最終調(diào)用destroy_vm()方法。
總結(jié)下就是:Java 程序在 main 線(xiàn)程執(zhí)行退出時(shí),會(huì)觸發(fā)執(zhí)行 JVM 退出操作(destroy_vm()方法),但是該方法會(huì)等待所有非守護(hù)線(xiàn)程(用戶(hù)線(xiàn)程)都執(zhí)行完,具體原理是使用變量_number_of_non_daemon_threads統(tǒng)計(jì)非守護(hù)線(xiàn)程的數(shù)量,這個(gè)變量在新增線(xiàn)程和刪除線(xiàn)程時(shí)會(huì)做增減操作。
另外衍生一點(diǎn)就是:當(dāng) JVM 退出時(shí),所有還存在的守護(hù)線(xiàn)程會(huì)被拋棄,既不會(huì)執(zhí)行 finally 部分代碼,也不會(huì) catch 異常。這個(gè)很明顯,JVM 都退出了,守護(hù)線(xiàn)程也就不能獨(dú)自存在了。
好了,以上就是今天的內(nèi)容分享,感謝大家的收看,我們下篇見(jiàn)。
審核編輯:湯梓紅
-
JAVA
+關(guān)注
關(guān)注
19文章
2966瀏覽量
104700 -
代碼
+關(guān)注
關(guān)注
30文章
4779瀏覽量
68521 -
JVM
+關(guān)注
關(guān)注
0文章
158瀏覽量
12220 -
線(xiàn)程
+關(guān)注
關(guān)注
0文章
504瀏覽量
19675
原文標(biāo)題:京東一面:守護(hù)線(xiàn)程如何實(shí)現(xiàn)的?
文章出處:【微信號(hào):CodeSheep,微信公眾號(hào):CodeSheep】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論