目錄
為什么存在
什么是守護線程
創建守護線程
在使用守護線程時需要注意以下幾點
可以使用isDaemon()方法來檢查線程是否是守護線程
例1:上面提到當JVM中只剩下守護線程的時候,JVM就會退出,那么寫段代碼測試下
例2:thread是用戶線程,主線程結束后,thread會繼續運行
例3:thread是守護線程,主線程結束后,thread會隨即停止
為什么存在
- Java程序入口就是由JVM啟動main線程,main線程又可以啟動其他線程
- 當所有線程都運行結束時,JVM退出,進程結束
- 如果有一個線程沒有退出,JVM進程就不會退出
- 所以,必須保證所有線程都能及時結束
- 但是有一種線程的目的就是無限循環
- 例如,一個定時觸發任務的線程:
- 如果這個線程不結束,JVM進程就無法結束
- 問題是,由誰負責結束這個線程?
- 然而這類線程經常沒有負責人來負責結束它們
- 但是,當其他線程結束時,JVM進程又必須要結束,怎么辦?
- 答案是使用守護線程(Daemon Thread)
- 守護線程是指為其他線程服務的線程
- 在JVM中,所有非守護線程都執行完畢后,無論有沒有守護線程,虛擬機都會自動退出
- 因此,JVM退出時,不必關心守護線程是否已結束
什么是守護線程
- 在Java中有兩類線程:User Thread(用戶線程)、Daemon Thread(守護線程)
- 它們通過Thread的daemon屬性標識:true表示守護線程,false表示用戶線程
- 用戶線程一般用于執行用戶級任務
- 而守護線程也就是“后臺線程”,一般用來執行后臺任務
- 并且這種線程并不屬于程序中不可或缺的部分
- 因此,當所有的非守護線程結束時,程序也就終止了
- 同時會殺死進程中的所有守護線程
- 反過來說,只要任何非守護線程還在運行,程序就不會終止
- 守護線程最典型的應用就是GC(垃圾回收器)
- 這兩種線程其實是沒有什么區別的
- 唯一的區別就是Java虛擬機在所有<用戶線程>都結束后就會退出,而不會等<守護線程>執行完
- 當所有的非守護線程結束時,程序也就終止了
- 因為沒有了被守護者,守護線程也就沒有工作可做了,也就沒有繼續運行程序的必要了
- GC線程就是一個守護線程,保持低優先級進行垃圾回收,不依賴系統資源
- 當所有用戶線程退出之后,GC線程也就沒有什么用了,會隨即退出
- 因為如果沒有用戶線程了,也就代表沒有垃圾會繼續產生,也就不需要GC線程了
- 可以簡單理解成守護線程為用戶線程服務,當所有用戶線程結束,也就不需要守護線程了
創建守護線程
- 將線程轉換為守護線程可以通過調用Thread對象的setDaemon(true)方法來實現,使線程成為一個守護線程
在使用守護線程時需要注意以下幾點
- 1-thread.setDaemon(true)必須在thread.start()之前設置,否則會拋出一個IllegalThreadStateException異常
- 你不能把正在運行的常規線程設置為守護線程
- 2-在Daemon線程中產生的新線程也是Daemon的
- 3-守護線程應該永遠不去訪問固有資源,如文件、數據庫,因為它會在任何時候甚至在一個操作的中間發生中斷,這會導致數據丟失
可以使用isDaemon()方法來檢查線程是否是守護線程
- 以上代碼輸出結果:
例1:上面提到當JVM中只剩下守護線程的時候,JVM就會退出,那么寫段代碼測試下
- 以上代碼中,我們在Main線程中開啟了一個子線程
- 在并沒有顯示將其設置為守護線程的情況下,他是一個用戶線程
- 代碼比較好理解,就是子線程處于一個while(true)循環中,每隔一秒打印一次I'm child thread..
- 輸出結果為:
- 我們再把子線程設置成守護線程,重新運行以上代碼:
- 以上代碼,我們通過childThread.setDaemon(true);把子線程設置成守護線程,然后運行,得到以下結果:
- 子線程只打印了一次
- 也就是在main線程執行結束后,由于子線程是一個守護線程,JVM就會直接退出了
- 值得注意的是,在Daemon線程中產生的新線程也是Daemon的