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

Java 執行緒控制核心技術:join、Daemon、sleep/yield 與優先級深度解析

     編輯:Java 綜合教學

Java 執行緒控制核心技術:join、Daemon、sleep/yield 與優先級深度解析

多執行緒程式設計中,執行緒之間的協作與控制是核心課題。Java 提供了豐富的 API 讓開發者精確掌控執行緒生命週期、調度順序與資源競爭。本文深度解析四大核心控制機制:join 等待合併、Daemon 守護執行緒、sleep/yield 讓出 CPU與執行緒優先級,附完整程式碼範例與執行行為分析。

一、join():主執行緒等待子執行緒完成

核心語義

呼叫 `thread.join()` 會讓當前執行緒(通常是主執行緒)進入阻塞狀態,直到目標執行緒 `thread` 執行結束(正常結束或拋出異常)為止。常用於「分治法」:主執行緒分派子任務,待所有子任務完成後再匯總結果。

程式碼範例

public class JoinThreadTest extends Thread {
    public JoinThreadTest(String name) { super(name); }
    
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + " " + i);
        }
    }
    
    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            if (i == 20) {
                JoinThreadTest joinThread = new JoinThreadTest("JoinThread");
                joinThread.start();
                try {
                    joinThread.join(); // 主執行緒阻塞,等待 JoinThread 跑完 0~99
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

執行流程解析

  1. 主執行緒跑到 `i==20`,啟動 `JoinThread`。
  2. 主執行緒呼叫 `join()` 進入 WAITING 狀態。
  3. `JoinThread` 獨佔 CPU 輸出 0~99。
  4. `JoinThread` 結束,主執行緒從 `join()` 返回,繼續輸出 21~999。

進階用法

  • `join(long millis)`:設定最長等待時間,超時自動返回(不拋異常)。
  • 多執行緒 `join` 串聯:`t1.join(); t2.join(); t3.join();` 確保順序完成。

二、Daemon 守護執行緒:隨 JVM 退出而自動終止

核心規則

  • 主執行緒預設為使用者執行緒。
  • 使用者執行緒建立的執行緒預設也是使用者執行緒;守護執行緒建立的預設為守護執行緒。
  • 當所有使用者執行緒結束,JVM 會自動終止所有守護執行緒並退出,不會等待它們完成。
  • 必須在 `start()` 之前呼叫 `setDaemon(true)`,否則拋 `IllegalThreadStateException`。
  • 用 `isDaemon()` 判斷類型。

程式碼範例

public class DaemonThreadTest extends Thread {
    public DaemonThreadTest(String name) { super(name); }
    
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(getName() + " " + i);
        }
    }
    
    public static void main(String[] args) {
        DaemonThreadTest daemon = new DaemonThreadTest("DaemonThread");
        daemon.setDaemon(true); // 必須在 start() 前
        daemon.start();
        
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
        // 主執行緒跑完 0~99 結束,JVM 退出,DaemonThread 只能輸出部分數字
    }
}

適用場景

  • 背景定時掃描、快取清理、日誌批次寫入、監控心跳等非關鍵、可中斷的輔助任務。
  • 不可用於:必須完成的業務邏輯、資料持久化、交易提交等關鍵操作。

三、sleep() 與 yield():釋放 CPU 的兩種姿勢

特性sleep(millis)yield()
狀態轉換RUNNING → TIMED_WAITING(阻塞)RUNNING → RUNNABLE(就緒)
CPU 佔用睡眠期間完全不佔用 CPU僅暫時讓出,調度器可能立即再次選中
影響範圍所有優先級執行緒僅影響優先級 ≥ 當前執行緒的執行緒
異常處理拋 InterruptedException,需 try-catch不拋受檢異常
典型用途定時輪詢、延遲重試、模擬耗時操作禮讓同優先級執行緒、避免佔用過久

yield() 優先級互動範例

public class YieldTest extends Thread {
    public YieldTest(String name) { super(name); }
    
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + " " + i);
            if (i == 20) Thread.yield();
        }
    }
    
    public static void main(String[] args) {
        YieldTest high = new YieldTest("High");
        high.setPriority(Thread.MAX_PRIORITY); // 10
        high.start();
        
        YieldTest low = new YieldTest("Low");
        low.setPriority(Thread.MIN_PRIORITY);  // 1
        low.start();
        
        // 結果:High 執行到 i=20 yield,但因優先級高,調度器大概率再次選中 High 繼續跑完
        // 若註解掉 setPriority,兩者優先級相同,yield 後 Low 獲得執行機會機率大增
    }
}

四、執行緒優先級:調度的參考依據

  • 範圍:`MIN_PRIORITY (1)` ~ `NORM_PRIORITY (5)` ~ `MAX_PRIORITY (10)`。
  • 子執行緒預設繼承父執行緒優先級。
  • 優先級只是調度器的「建議」,不保證執行順序,受 OS 調度策略影響極大。
  • 避免依賴優先級實現業務邏輯正確性(如互斥、同步),應用 `synchronized`、`Lock`、`CountDownLatch` 等同步機制。

五、綜合選型指南

需求推薦 API備註
主執行緒等待子任務完成join() / CountDownLatch / CompletableFuture現代開發優先考慮高層併發工具
背景非關鍵任務Daemon Thread / ScheduledExecutorService避免阻塞 JVM 關閉
固定間隔/延遲執行sleep() / ScheduledExecutorServicesleep 精度受 OS 影響,約 10-15ms
禮讓 CPU 給同優先級執行緒yield()極少直接使用,通常由鎖/同步器隱含處理
調整執行緒重要性setPriority()僅作微調,不可作為同步手段

結語

掌握 `join`、`Daemon`、`sleep/yield` 與優先級的語義差異與適用邊界,是編寫高併發、高穩定性 Java 程式的基石。實務中,優先使用 `java.util.concurrent` 套件提供的高層抽象(`ExecutorService`、`Future`、`CompletableFuture`、`CountDownLatch`、`Semaphore` 等),僅在極簡單場景或框架底層直接操作 `Thread` 原生 API,能顯著降低併發 Bug 風險並提升程式碼可維護性。

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