定義和概述
Java 中的線程分為兩類,分別為daemon 線程(守護線程〉和user 線程(用戶線程)。守護線程又稱Daemon線程,運行在後台,看不見;用戶線程運行在前台,看的見。
在JVM啟動時會調用main 函數, main 函數所在的線程就是一個用戶線程,其實在JVM內部同時-還啟動了好多守護線程, 比如垃圾回收線程。
Daemon線程是一種支持型線程,因為它主要被用作程序中後台調度以及支持性工作。這意味着,當一個Java虛擬機中不存在非Daemon線程的時候,Java虛擬機將會退出,而不管當前是否有守護線程,也就是說守護線程是否結束並不影響JVM的退出。
實際上,在main線程運行結束後,JVM會自動啟動一個叫作DestroyJavaVM 的線程,該線程會等待所有用戶線程結束後終止JVM 進程。
在Tomcat的NIO實現NioEndpoint中會開啟一組接受線程來接受用戶的連接請求,以及一組處理線程負責具體處理用戶請求,在默認情況下,接受線程和處理線程都是守護線程,這意味着當tomcat 收到shutdown 命令後並且沒有其他用戶線程存在的情況下tomcat 進程會馬上消亡,而不會等待處理線程處理完當前的請求。
2 使用守護線程
在線程start之前,可以通過調用thread.setDaemon(true)將線程設置為Daemon線程。
守護線程有兩種結束方式:
- 守護線程也具有自己的run();方法,當後台線程完成自己的run方法後,守護線程結束。
- 用戶線程運行結束,守護線程自動結束。
3 測試案例
public class Daemon {
//啟動該類,將會構造兩條線程,main線程和一條子線程。
public static void main(String[] args) throws InterruptedException {
//測試非守護線程
//可以看到,輸出"main線程結束"之後,子線程還在繼續輸出,程序沒有結束
// test1();
//測試守護線程
//可以看到,輸出"main線程結束"之後,子線程沒有繼續輸出,程序結束
test2();
}
/**
* 測試非守護線程
*
* @throws InterruptedException
*/
public static void test1() throws InterruptedException {
Thread thread = new Thread(() -> {
while (true) {
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子線程非守護線程");
}
});
thread.start();
Thread.currentThread().sleep(1000);
System.out.println("main線程結束");
}
//測試守護線程
public static void test2() throws InterruptedException {
Thread thread = new Thread(() -> {
while (true) {
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子線程守護線程");
}
});
thread.setDaemon(true);
thread.start();
Thread.currentThread().sleep(1000);
System.out.println("main線程結束");
}
}
複製代碼
使用jps查看java進程,可以發現如果子線程是守護線程那麼主線程結束,子線程也結束了;如果子線程不是守護線程那麼主線程結束,子線程沒有結束。

4 注意事項
Daemon線程被用作完成支持性工作,但是在Java虛擬機退出時Daemon線程中的finally塊並不一定會執行,如下代碼:
public class Daemon {
public static void main(String[] args) {
Thread thread = new Thread(new DaemonRunner(), "DaemonRunner");
thread.setDaemon(true);
thread.start();
}
static class DaemonRunner implements Runnable {
@Override
public void run() {
try {
SleepUtils.second(10);
} finally {
System.out.println("DaemonThread finally run.");
}
}
}
}
複製代碼
運行Daemon程序,可以看到在控制台上沒有任何輸出。main線程(非Daemon線程)在啟動了線程DaemonRunner之後隨着main方法執行完畢而終止,而此時Java虛擬機中已經沒有非Daemon線程,虛擬機需要退出。Java虛擬機中的所有Daemon線程都需要立即終止,因此DaemonRunner立即終止,但是DaemonRunner中的finally塊並沒有執行。
在構建Daemon線程時,不能依靠finally塊中的內容來確保執行關閉或清理資源的邏輯。
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/220618.html