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

Java Thread.join() 詳解:線程等待與合併執行的核心機制

     編輯:Java 綜合教學

Java Thread.join() 詳解:線程等待與合併執行的核心機制

Thread.join() 是實現「線程順序執行」的關鍵方法:調用線程(通常是主線程)阻塞等待,直到目標線程運行結束。本文通過代碼示例演示 join() 行為,並補充線程優先級與 yield() 協作式調度知識。

一、join() 核心語義與代碼演示

class JoinTestDemo implements Runnable {
    @Override
    public void run() {
        for (int x = 0; x <= 5; x++) {
            try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(Thread.currentThread().getName() + "====" + x);
        }
    }
}

public class JoinDemo {
    public static void main(String[] args) throws InterruptedException {
        JoinTestDemo task = new JoinTestDemo();
        Thread t1 = new Thread(task, "Thread-1");
        Thread t2 = new Thread(task, "Thread-2");
        t1.start();
        t2.start();

        // 主線程阻塞,等待 t1 完全結束
        t1.join(); 

        // t1 結束後,主線程繼續執行
        for (int x = 0; x <= 5; x++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + "====" + x);
        }
    }
}

二、運行結果分析

join() 運行結果截圖

輸出順序:

  1. Thread-1 和 Thread-2 交替輸出 0~5(併發運行)。
  2. Thread-1 運行結束(約 600ms)。
  3. 主線程從 t1.join() 返回,開始輸出 main====0~5。
  4. 注意:Thread-2 可能仍在運行,但主線程不再等待它(除非再調用 t2.join())。

三、join() 重載版本

  • join():無限期等待。
  • join(long millis):最多等待指定毫秒,超時返回(不拋異常,需自行檢查 isAlive())。
  • join(long millis, int nanos):納秒級精度超時等待。

四、底層原理

join() 內部調用 wait(0) 循環,釋放鎖並進入 WAITING 狀態。目標線程終止時,JVM 自動調用 notifyAll() 喚醒等待線程。源碼片段:

public final synchronized void join(long millis) throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;
    if (millis < 0) throw new IllegalArgumentException("timeout value is negative");
    if (millis == 0) {
        while (isAlive()) wait(0);
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) break;
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

五、補充:線程優先級與 yield()

  • 優先級:setPriority(int),範圍 1(MIN_PRIORITY)~10(MAX_PRIORITY),默認 5(NORM_PRIORITY)。僅是調度器參考提示,不保證執行順序。
  • yield():Thread.yield() 暫時放棄 CPU 時間片,讓同優先級線程有機會執行。屬協作式調度,不可靠,僅用於測試/調試。

六、最佳實踐

  1. 主線程等待多個工作線程結束:循環調用 thread.join() 或使用 CountDownLatch/CompletableFuture.allOf() 更優雅。
  2. 帶超時的 join(millis) 防止死等異常線程,超時後記錄日誌、發送告警、嘗試 interrupt()。
  3. 避免在持有鎖時調用 join(),極易產生死鎖。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved