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

Java 多線程 join() 死鎖之謎:匿名內部類 this 指向與 isAlive() 機制深度解析

     編輯:程式設計綜合問答

問題代碼


public class SigleThread extends Thread {
    @Override public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(i);
            try { join(); } catch (InterruptedException e) { e.printStackTrace(); }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        SigleThread sing = new SigleThread();
        sing.start(); // 啟動 sing 執行緒
    }
}

現象

主控台輸出 0 後永久卡住 (死鎖)。

根因逐層剖析

  1. sing.start() 啟動新執行緒 (稱 **Thread-0**),執行 run()。
  2. run() 內部呼叫 join() → 實為 this.join(),此處 this 指向 **sigleThread 實例 (sing)**。
  3. Thread.join() 源碼邏輯:
    while (isAlive()) wait(0);
    即:**若當前執行緒對象仍存活,則無限等待**。
  4. sing (Thread-0) 正在執行 run(),故 isAlive() == true → **自己等待自己** → 永久阻塞。

對比:Runnable + new Thread() 寫法為何正常?


Runnable sing = new SigleThread(); // 只是 Runnable 實例,非 Thread
Thread t = new Thread(sing);       // 建立新 Thread 物件 (Thread-1)
t.start();                         // 啟動 Thread-1,執行 sing.run()
  • run() 內的 this 仍指向 sing (Runnable 實例)。
  • sing **從未被 start()**,故 sing.isAlive() == false。
  • join() 發現 !isAlive() 直接返回,**不阻塞**,迴圈繼續輸出 1~4。

核心觀念總結

寫法run() 中 thisisAlive()join() 行為
Thread 子類 + start()Thread 實例 (自己)true (正在跑)**自己等自己 → 死鎖**
Runnable + new Thread(r).start()Runnable 實例 (非執行緒)false (未啟動)立即返回 → 正常

最佳實踐

  • **切勿在 Thread 子類的 run() 中呼叫 join()** —— 邏輯上極少合理。
  • 若需等待其他執行緒,持有該執行緒引用並呼叫 otherThread.join()。
  • 優先使用 ExecutorService、CompletableFuture、CountDownLatch 等高層協作工具,避免手動管理 Thread 生命週期。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved