線程 start() 立即返回,run() 異步執行。主線程若直接讀取線程字段,大概率遇到 可見性問題(讀到 null/舊值)或 時序問題(線程尚未寫入)。
MyThread t = new MyThread();
t.start();
System.out.println(t.result); // 極大概率印 null
public class JoinDemo extends Thread {
private String result;
@Override
public void run() {
// 模擬耗時計算
try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
result = "計算完成: " + System.currentTimeMillis();
}
public static void main(String[] args) throws InterruptedException {
JoinDemo t = new JoinDemo();
t.start();
t.join(); // 關鍵:阻塞主線程,直到 t 終止
// join() 返回時,JMM 保證 t.run() 所有寫入對主線程可見
System.out.println(t.result); // 必見真實結果
}
}
原理:Thread.join() 底層調用 wait(),線程終止前調用 notifyAll()。JMM 保證:線程終止前的所有寫入,對成功從 join() 返回的線程可見(happens-before 規則)。
// 低效且不保證可見性(無同步動作)
while (t.result == null) { /* busy spin */ }
// 改良:睡眠輪詢 (仍不保證可見性,除非 result 為 volatile)
while (t.result == null) { Thread.sleep(100); }
結論:永遠優先使用 join(),簡潔、正確、高效(無忙等)。
當主線程不能/不願阻塞時,將「結果處理邏輯」作為回調傳入線程:
// 回調接口
interface ResultHandler {
void onResult(String result);
void onError(Throwable t);
}
// 線程實現
public class CallbackThread extends Thread {
private final ResultHandler handler;
public CallbackThread(ResultHandler handler) {
this.handler = handler;
}
@Override
public void run() {
try {
String result = doHeavyWork();
handler.onResult(result);
} catch (Throwable e) {
handler.onError(e);
}
}
}
// 使用:主線程繼續幹別的事
new CallbackThread(new ResultHandler() {
@Override public void onResult(String r) {
System.out.println("異步收到結果: " + r);
updateUI(r); // 如 Swing/JavaFX 需在 EDT 執行
}
@Override public void onError(Throwable t) { log.error("失敗", t); }
}).start();
System.out.println("主線程未阻塞,繼續執行...");
| API | 適用場景 | 核心優勢 |
|---|---|---|
Future<T> / Callable<T> | 需要阻塞獲取結果、可取消 | 標準化、支援超時、異常傳播 |
CompletableFuture<T> | 異步鏈式處理、多任務編排 | 非阻塞、函數式組合、異常處理豐富 |
ExecutorService.submit() | 線程池管理、資源復用 | 生產級、可監控、拒絕策略 |
CompletableFuture.supplyAsync() | 簡單異步計算 | 一行代碼、默認公共池 |
// 異步計算 + 異步回調 + 異常處理
CompletableFuture.supplyAsync(() -> {
Thread.sleep(1000);
return "異步結果";
}).thenAccept(result -> {
System.out.println("收到: " + result);
}).exceptionally(ex -> {
log.error("異步失敗", ex);
return null;
});
// 主線程繼續...
Thread.join() + 共享字段(字段建議 volatile)ExecutorService.submit(Callable) 返回 FutureCompletableFuture 鏈式編程wait/notify、忙等輪詢、非 volatile 共享字段掌握 happens-before 原則 與 高級併發 API,是寫出正確、高性能並發代碼的關鍵。