多線程是 Java 並發編程的基石。掌握繼承 Thread、實現 Runnable、實現 Callable+Future 三種核心創建方式,理解它們的異同、優缺點及適用場景,是寫出高質量並發代碼的前提。本文深度對比三種方式,並延伸至線程池、CompletableFuture 等現代最佳實踐。
public class MyThread extends Thread {
@Override
public void run() {
// 線程執行邏輯
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
}
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start(); // 必須調用 start() 啟動新線程,JVM 會調用 run()
t2.start();
// 直接調用 t1.run() 是單線程順序執行!
}
}
this 即線程對象,易獲取線程名/ID。
public class MyTask implements Runnable {
private final String taskName;
public MyTask(String taskName) { this.taskName = taskName; }
@Override
public void run() {
System.out.println(taskName + " running in " + Thread.currentThread().getName());
}
public static void main(String[] args) {
MyTask task1 = new MyTask("Task-A");
MyTask task2 = new MyTask("Task-B");
// 必須包裝進 Thread 對象啟動
new Thread(task1).start();
new Thread(task2).start();
// 或提交給線程池 (推薦)
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(task1);
pool.submit(task2);
pool.shutdown();
}
}
() -> { ... }。
import java.util.concurrent.*;
public class MyCallable implements Callable {
private final int id;
public MyCallable(int id) { this.id = id; }
@Override
public String call() throws Exception {
Thread.sleep(1000); // 模擬耗時
if (id == 3) throw new RuntimeException("Task 3 failed!");
return "Result of Task-" + id;
}
public static void main(String[] args) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(3);
List> futures = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
Future f = pool.submit(new MyCallable(i)); // 提交返回 Future
futures.add(f);
}
// 獲取結果 (阻塞直到完成)
for (Future f : futures) {
try {
System.out.println("Got: " + f.get()); // 獲取返回值或拋出異常
} catch (ExecutionException e) {
System.err.println("Task failed: " + e.getCause().getMessage());
}
}
pool.shutdown();
}
}
Future 可異步獲取結果/取消/超時控制。get() 阻塞、需處理 InterruptedException/ExecutionException)。| 維度 | extends Thread | implements Runnable | implements Callable |
|---|---|---|---|
| 返回值 | 無 | 無 | 有 (泛型) |
| 拋受檢異常 | 無 | 無 | 可拋 |
| 單繼承限制 | 受限 | 無 | 無 |
| 任務/線程耦合 | 強耦合 | 解耦 | 解耦 |
| 線程池適配 | 差 | 完美 | 完美 |
| Lambda 支持 | 無 | 完美 | 完美 |
| 結果獲取方式 | 共享變量/回調 | 共享變量/回調 | Future.get() |
不再手動創建 Thread! 生產環境統一使用線程池管理線程生命週期,配合 CompletableFuture 進行異步編排。
// 自定義線程池,拒絕默認無界隊列 (OOM 風險)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100), // 有界隊列
new ThreadFactoryBuilder().setNameFormat("biz-%d").build(), // 命名便於排查
new ThreadPoolExecutor.AbortPolicy() // 拒絕策略
);
// 供給異步任務
CompletableFuture f1 = CompletableFuture.supplyAsync(() -> {
return heavyCompute("A");
}, executor);
// 異步回調鏈
CompletableFuture f2 = f1.thenApply(res -> res.toUpperCase())
.thenAccept(System.out::println)
.exceptionally(ex -> { log.error("Failed", ex); return null; });
// 多任務組合
CompletableFuture.allOf(f1, f2, f3).join(); // 等待全部完成
CompletableFuture.anyOf(f1, f2).join(); // 等待任意一個完成
synchronized / Lock / Atomic* / Concurrent* 集合。extends Thread,耦合度高、擴展性差。implements Runnable + 線程池,任務解耦、通用性最強。Callable + Future 或 CompletableFuture。Executors.xxx 默認工廠 (無界隊列 OOM 風險),**自定義 ThreadPoolExecutor**。理解三種方式本質,是為了在實際架構中做正確選型:**任務提交給線程池,結果用 Future/CompletableFuture 接收,狀態用同步工具守護**。這才是 Java 並發工程化的正確打開方式。