線程優先級與守護線程是 Java 線程模型的兩個基本屬性。優先級影響調度順序,守護線程決定 JVM 退出時機。本文通過規格文檔解讀、代碼實驗與輸出分析,徹底講透這兩個概念。
MIN_PRIORITY)~ 10(MAX_PRIORITY),默認 5(NORM_PRIORITY)。new Thread() 時優先級 = 創建者優先級。class MyThread extends Thread {
public MyThread(String name) { super(name); }
public void run() {
for (int i = 0; i < 5; i++)
System.out.println(getName() + "(" + getPriority() + "), loop " + i);
}
}
public class Demo {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "(" + Thread.currentThread().getPriority() + ")");
Thread t1 = new MyThread("t1"); t1.setPriority(1);
Thread t2 = new MyThread("t2"); t2.setPriority(10);
t1.start(); t2.start();
}
}
main(5) t1(1), loop 0 t2(10), loop 0 t1(1), loop 1 t2(10), loop 1 t1(1), loop 2 t2(10), loop 2 t1(1), loop 3 t2(10), loop 3 t1(1), loop 4 t2(10), loop 4
main 優先級 5。t1 設置為 1,t2 設置為 10。t2 全跑完再跑 t1。原因:時間片輪轉調度,優先級只是概率性傾向,非強制搶佔。isDaemon() 區分:false = 用戶線程,true = 守護線程。class MyThread extends Thread { // 用戶線程
public void run() {
for (int i = 0; i < 5; i++) { sleep(3); System.out.println(getName() + "(isDaemon=" + isDaemon() + "), loop " + i); }
}
}
class MyDaemon extends Thread { // 守護線程
public void run() {
for (int i = 0; i < 10000; i++) { sleep(1); System.out.println(getName() + "(isDaemon=" + isDaemon() + "), loop " + i); }
}
}
public class Demo {
public static void main(String[] args) {
Thread t1 = new MyThread("t1");
Thread t2 = new MyDaemon("t2"); t2.setDaemon(true);
t1.start(); t2.start();
}
}
main(isDaemon=false) t2(isDaemon=true), loop 0 t2(isDaemon=true), loop 1 t1(isDaemon=false), loop 0 t2(isDaemon=true), loop 2 t2(isDaemon=true), loop 3 t1(isDaemon=false), loop 1 t2(isDaemon=true), loop 4 t2(isDaemon=true), loop 5 t2(isDaemon=true), loop 6 t1(isDaemon=false), loop 2 t2(isDaemon=true), loop 7 t2(isDaemon=true), loop 8 t2(isDaemon=true), loop 9 t1(isDaemon=false), loop 3 t2(isDaemon=true), loop 10 t2(isDaemon=true), loop 11 t1(isDaemon=false), loop 4 t2(isDaemon=true), loop 12 // 程序結束,t2 還有 9987 次循環未執行
main 和 t1 為用戶線程,t2 為守護線程。t1 執行完 5 次循環結束,main 也結束 → JVM 檢測到無用戶線程 → 強制退出。t2 即使循環未完成,也被強制終止(不執行 finally、不釋放鎖、不執行 shutdown hook)。| 場景 | 風險 | 對策 |
|---|---|---|
| 守護線程持有資源(文件、鎖、連接) | JVM 退出時資源洩漏、數據損壞 | 守護線程勿持有需顯式釋放的資源,或註冊 ShutdownHook 清理 |
| 業務線程誤設為守護線程 | 主線程結束導致業務中斷 | 業務線程必須為用戶線程(默認) |
| 需優雅關閉後台任務 | 守護線程無法優雅關閉 | 用用戶線程 + volatile boolean running 標記 + interrupt() 協作式停止 |
| 屬性 | 用戶線程 | 守護線程 |
|---|---|---|
isDaemon() | false | true |
| 典型用途 | 業務處理、請求處理、計算任務 | GC、JIT、監控、定時清理、日誌刷盤 |
| JVM 退出影響 | 阻止 JVM 退出 | 不阻止,隨 JVM 退出而強制終止 |
| 子線程默認屬性 | 用戶線程 | 守護線程 |
| 優先級繼承 | 繼承父線程優先級 | 繼承父線程優先級 |
優先級是「調度建議」,守護線程是「生命週期標記」。實戰中:
理解這兩個屬性的語義邊界,能避免「主線程結束業務莫名中斷」「守護線程導致資源洩漏」等經典生產事故。