首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 多線程基礎:線程優先級與守護線程詳解

     編輯:Java 相關知識

前言

線程優先級與守護線程是 Java 線程模型的兩個基本屬性。優先級影響調度順序,守護線程決定 JVM 退出時機。本文通過規格文檔解讀、代碼實驗與輸出分析,徹底講透這兩個概念。

一、線程優先級

1. 規格定義

  • 範圍:1(MIN_PRIORITY)~ 10(MAX_PRIORITY),默認 5(NORM_PRIORITY)。
  • 高優先級線程傾向於獲得更多 CPU 時間片,但不保證執行順序(受 OS 調度器、時間片輪轉影響)。
  • 子線程繼承父線程優先級:new Thread() 時優先級 = 創建者優先級。

2. 實驗代碼與輸出

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

3. 結果分析

  • 主線程 main 優先級 5。
  • t1 設置為 1,t2 設置為 10。
  • 輸出呈現交替執行,而非 t2 全跑完再跑 t1。原因:時間片輪轉調度,優先級只是概率性傾向,非強制搶佔。

4. 實戰建議

  1. 不要依賴優先級實現業務邏輯正確性(如互斥、順序),它只是調度提示。
  2. 默認優先級通常足夠;僅在明確需要「後台低優先級計算任務」時降低優先級。
  3. 高優先級濫用會導致低優先級線程飢餓。

二、守護線程

1. 核心規則

  • isDaemon() 區分:false = 用戶線程,true = 守護線程。
  • 用戶線程執行用戶級任務;守護線程執行後台支撐任務(GC、JIT 編譯、監控等)。
  • JVM 退出條件:所有用戶線程結束 → JVM 自動退出,無論守護線程是否還在運行。
  • 子線程守護性繼承:父線程是守護線程 → 子線程默認也是守護線程。

2. 實驗代碼與輸出

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 次循環未執行

3. 結果分析

  • main 和 t1 為用戶線程,t2 為守護線程。
  • t1 執行完 5 次循環結束,main 也結束 → JVM 檢測到無用戶線程 → 強制退出。
  • t2 即使循環未完成,也被強制終止(不執行 finally、不釋放鎖、不執行 shutdown hook)。

4. 實戰陷阱與最佳實踐

場景風險對策
守護線程持有資源(文件、鎖、連接)JVM 退出時資源洩漏、數據損壞守護線程勿持有需顯式釋放的資源,或註冊 ShutdownHook 清理
業務線程誤設為守護線程主線程結束導致業務中斷業務線程必須為用戶線程(默認)
需優雅關閉後台任務守護線程無法優雅關閉用用戶線程 + volatile boolean running 標記 + interrupt() 協作式停止

三、總結對照表

屬性用戶線程守護線程
isDaemon()falsetrue
典型用途業務處理、請求處理、計算任務GC、JIT、監控、定時清理、日誌刷盤
JVM 退出影響阻止 JVM 退出不阻止,隨 JVM 退出而強制終止
子線程默認屬性用戶線程守護線程
優先級繼承繼承父線程優先級繼承父線程優先級

結語

優先級是「調度建議」,守護線程是「生命週期標記」。實戰中:

  1. 業務線程保持用戶線程、默認優先級。
  2. 後台輔助任務(非核心、可丟失)設為守護線程,且不持有關鍵資源。
  3. 需優雅關閉的後台任務,用用戶線程 + 協作式停止標記,絕不用守護線程。

理解這兩個屬性的語義邊界,能避免「主線程結束業務莫名中斷」「守護線程導致資源洩漏」等經典生產事故。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved