Java并發(fā)編程:守護(hù)線程
什么是守護(hù)線程?
與普通線程相比,守護(hù)線程(Daemon Thread)是一種特殊類型的線程。它的特殊性體現(xiàn)在哪里?在理解之前,我們需要先明確一個(gè)問題:
Java程序在什么情況下會(huì)正常退出?當(dāng)JVM中唯一運(yùn)行的線程都是守護(hù)線程時(shí),Java虛擬機(jī)才會(huì)退出。這句話源自JDK官方文檔,即:當(dāng)JVM中沒有正在運(yùn)行的非守護(hù)線程時(shí),JVM進(jìn)程會(huì)退出。
直接理解可能有些抽象,但通過以下代碼示例會(huì)更清晰:
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
// 創(chuàng)建一個(gè)用戶線程(非守護(hù)線程)
Thread userThread = new Thread(() -> {
// 無限循環(huán)
while (true) {
System.out.println("用戶線程正在運(yùn)行...");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
userThread.start();
Thread.sleep(1000);
// 添加關(guān)閉鉤子
Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("關(guān)閉鉤子正在運(yùn)行...")));
System.out.println("主線程即將執(zhí)行完畢");
}
}
我們創(chuàng)建了一個(gè)用戶線程,其邏輯是無限循環(huán)。運(yùn)行這段代碼后,猜猜主線程結(jié)束后,JVM進(jìn)程會(huì)自動(dòng)退出嗎?
輸出結(jié)果:
用戶線程正在運(yùn)行...
主線程即將執(zhí)行完畢
用戶線程正在運(yùn)行...
用戶線程正在運(yùn)行...
用戶線程正在運(yùn)行...
用戶線程正在運(yùn)行...
...
可以看到,由于后臺(tái)始終有一個(gè)非守護(hù)線程在運(yùn)行,JVM無法正常自動(dòng)退出,且關(guān)閉鉤子(ShutdownHook)的邏輯也不會(huì)執(zhí)行。程序會(huì)每隔2秒持續(xù)輸出“用戶線程正在運(yùn)行...”。那么,如果是守護(hù)線程運(yùn)行會(huì)怎樣?
通過Thread.setDaemon(true)方法將線程設(shè)置為守護(hù)線程。代碼如下:
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
// 創(chuàng)建一個(gè)守護(hù)線程
Thread thread = new Thread(() -> {
// 無限循環(huán)
while (true) {
System.out.println("守護(hù)線程正在運(yùn)行...");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.setDaemon(true); // 設(shè)置為守護(hù)線程
thread.start();
Thread.sleep(1000);
Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("關(guān)閉鉤子正在運(yùn)行...")));
System.out.println("主線程即將執(zhí)行完畢");
}
}
再次運(yùn)行代碼,觀察結(jié)果:
輸出結(jié)果:
守護(hù)線程正在運(yùn)行...
主線程即將執(zhí)行完畢
關(guān)閉鉤子正在運(yùn)行...
可以看到,當(dāng)主線程退出時(shí),JVM會(huì)直接退出,守護(hù)線程也隨之終止。即使內(nèi)部有無限循環(huán),守護(hù)線程也會(huì)立即停止。
守護(hù)線程的作用與使用場景
作用
Java引入守護(hù)線程的主要目的是提供一種機(jī)制來支持后臺(tái)任務(wù)的執(zhí)行。守護(hù)線程在程序生命周期中扮演輔助角色,為其他線程提供支持和服務(wù)。
以垃圾回收線程(GC)為例,它是一個(gè)經(jīng)典的守護(hù)線程。當(dāng)程序中不再有任何運(yùn)行中的用戶線程時(shí),程序也不會(huì)再產(chǎn)生垃圾,垃圾回收線程也就無事可做。因此,當(dāng)JVM中只剩下垃圾回收線程時(shí),JVM會(huì)自動(dòng)退出。GC始終在后臺(tái)低優(yōu)先級(jí)運(yùn)行,實(shí)時(shí)監(jiān)控和管理系統(tǒng)中的可回收資源。
使用場景
- 后臺(tái)任務(wù)守護(hù)線程常用于執(zhí)行與主線程無關(guān)的后臺(tái)任務(wù),例如日志記錄、定時(shí)任務(wù)、監(jiān)控等。這些任務(wù)可以默默在程序后臺(tái)運(yùn)行,不影響主流程。
- 垃圾回收垃圾回收是JVM的重要功能,負(fù)責(zé)回收無用對(duì)象并釋放內(nèi)存。垃圾回收線程是守護(hù)線程,會(huì)在程序運(yùn)行時(shí)自動(dòng)執(zhí)行。
- 資源管理守護(hù)線程可用于資源管理,例如數(shù)據(jù)庫連接池中的線程池管理器。它可以監(jiān)控空閑連接,若連接長時(shí)間未使用,守護(hù)線程會(huì)自動(dòng)關(guān)閉連接以避免資源浪費(fèi)。
- 守護(hù)服務(wù)在服務(wù)器應(yīng)用中,守護(hù)線程常用于提供服務(wù)。例如,Web服務(wù)器中的守護(hù)線程可以監(jiān)聽客戶端請(qǐng)求。當(dāng)所有客戶端連接斷開后,守護(hù)線程會(huì)自動(dòng)關(guān)閉服務(wù)器。
注意事項(xiàng)守護(hù)線程的終止是不可控的。當(dāng)程序中只剩下守護(hù)線程時(shí),它會(huì)隨主線程結(jié)束而自動(dòng)終止。因此,使用守護(hù)線程時(shí)需確保任務(wù)可中斷或可恢復(fù),且不會(huì)影響程序的整體邏輯。