Java中的守護線程問題
守護線程
在Java中有兩類線程
- User Thread(用戶線程)
- Daemon Thread(守護線程)
守護線程的功能非常簡單,在其本身是一個線程的同時,主要是為了給其他的線程提供服務,比如說計時器,清空高速緩存等等操作,守護線程具有和被守護線程一樣的生命周期(這里并不是說守護線程和被守護線程常常是1-1的關系),當被守護線程死亡,守護線程往往也會死亡,當虛擬機中只剩下守護線程時,虛擬機就會退出,因為此時也沒有運行程序的必要了
一個比較通俗的解釋:任何一個守護線程都是整個JVM中所有非守護線程的保姆
只要當前JVM實例中尚存在任何一個非守護線程沒有結束,守護線程就全部工作;只有當最后一個非守護線程結束時,守護線程隨著JVM一同結束工作。
守護線程的作用是為其他線程的運行提供便利服務,守護線程最典型的應用就是 GC (垃圾回收器),它就是一個很稱職的守護者。
需要注意的點是:
- 守護線程的優(yōu)先級比較低
- 守護線程要注意考慮關機動作
- 守護線程應該永遠不去訪問固有資源,比如說文件或者數(shù)據(jù)庫,因為它會在任何時候甚至一個操作的中間發(fā)生中斷。
不要給守護線程分擔讀寫邏輯或者計算邏輯,因為無法確定守護線程是否已經(jīng)完成了工作,但是只要User退出守護線程也會立馬結束,對于計算機程序來說這樣的程序可能多次運行結果不一樣,很顯然這對于程序來說是毀滅性的。
操作:
通過thread.setDaemon(true) 將線程轉換為守護線程
這個方法必須在thread.start()之前進行調用
守護線程與用戶線程的區(qū)別
介紹Java守護線程與用戶線程的概念和使用方法,以及相關注意事項。
1 定義和概述
Java 中的線程分為兩類,分別為daemon 線程(守護線程〉和user 線程(用戶線程)。守護線程又稱Daemon線程,運行在后臺,看不見;用戶線程運行在前臺,看的見。
在JVM啟動時會調用main 函數(shù), main 函數(shù)所在的線程就是一個用戶線程,其實在JVM內部同時-還啟動了好多守護線程, 比如垃圾回收線程。
Daemon線程是一種支持型線程,因為它主要被用作程序中后臺調度以及支持性工作。這意味著,當一個Java虛擬機中不存在非Daemon線程的時候,Java虛擬機將會退出,而不管當前是否有守護線程,也就是說守護線程是否結束并不影響JVM的退出。
實際上,在main線程運行結束后,JVM會自動啟動一個叫作DestroyJavaVM 的線程,該線程會等待所有用戶線程結束后終止JVM 進程。
在Tomcat的NIO實現(xiàn)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線程結束"之后,子線程還在繼續(xù)輸出,程序沒有結束
// test1();
//測試守護線程
//可以看到,輸出"main線程結束"之后,子線程沒有繼續(xù)輸出,程序結束
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進程,可以發(fā)現(xiàn)如果子線程是守護線程那么主線程結束,子線程也結束了;如果子線程不是守護線程那么主線程結束,子線程沒有結束。

4 注意事項
Daemon線程被用作完成支持性工作,但是在Java虛擬機退出時Daemon線程中的finally塊并不一定會執(zhí)行,如下代碼:
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方法執(zhí)行完畢而終止,而此時Java虛擬機中已經(jīng)沒有非Daemon線程,虛擬機需要退出。Java虛擬機中的所有Daemon線程都需要立即終止,因此DaemonRunner立即終止,但是DaemonRunner中的finally塊并沒有執(zhí)行。
在構建Daemon線程時,不能依靠finally塊中的內容來確保執(zhí)行關閉或清理資源的邏輯。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Java?EasyExcel實現(xiàn)合并相同內容單元格與動態(tài)標題功能
這篇文章主要為大家詳細介紹了Java?EasyExcel如何實現(xiàn)合并相同內容單元格與動態(tài)標題功能,文中的示例代碼講解詳細,有需要的小伙伴可以參考下2023-12-12
Java操作mongodb增刪改查的基本操作實戰(zhàn)指南
MongoDB是一個基于分布式文件存儲的數(shù)據(jù)庫,由c++語言編寫,旨在為WEB應用提供可擴展的高性能數(shù)據(jù)存儲解決方案,下面這篇文章主要給大家介紹了關于Java操作mongodb增刪改查的基本操作實戰(zhàn)指南,需要的朋友可以參考下2023-05-05
MyBatis-Plus中靜態(tài)工具Db的多種用法及實例分析
本文將詳細講解MyBatis-Plus中靜態(tài)工具Db的各種用法,并結合具體案例進行演示和說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-03-03
SpringCloud集成MybatisPlus實現(xiàn)MySQL多數(shù)據(jù)源配置方法
本文詳細介紹了SpringCloud集成MybatisPlus實現(xiàn)MySQL多數(shù)據(jù)源配置的方法,包括在application.properties中配置多數(shù)據(jù)源,配置MybatisPlus,創(chuàng)建Mapper接口和使用多數(shù)據(jù)源等步驟,此外,還解釋了每一個配置項目的含義,以便讀者更好地理解和應用2024-10-10
Java AQS(AbstractQueuedSynchronizer)源碼解析
AbstractQueuedSynchronizer被稱為隊列同步器,簡稱為大家熟知的AQS,這個類可以稱作concurrent包的基礎。本文將通過剖析源碼來看看AQS是如何工作的,感興趣的可以了解一下2023-02-02
Java畢業(yè)設計之多用戶宿舍管理系統(tǒng)的實現(xiàn)
這篇文章主要介紹了基于Java實現(xiàn)的多用戶宿舍管理系統(tǒng),本文采用了jsp、servlet、jdbc等技術,文中示例代碼講解詳細,需要的可以參考一下2022-02-02
Java String方法獲取字符出現(xiàn)次數(shù)及字符最大相同部分示例
這篇文章主要介紹了Java String方法獲取字符出現(xiàn)次數(shù)及字符最大相同部分,涉及java字符串的遍歷、比較、計算等相關操作技巧,需要的朋友可以參考下2017-09-09

