| 維度 | 繼承 Thread | 實現 Runnable | 實現 Callable |
|---|---|---|---|
| 返回值 | 無 | 無 | 支援泛型返回值 |
| 拋出異常 | 不可拋受檢異常 | 不可拋受檢異常 | 可拋受檢異常 |
| 線程邏輯復用 | 差(繼承限制) | 優(同一 Runnable 可給多 Thread) | 優 |
| 適用場景 | 簡單獨立任務 | 大多數業務場景 | 需結果、需異常處理的異步任務 |
public class PrintTask extends Thread {
private final int limit;
public PrintTask(int limit) {
this.limit = limit;
}
@Override
public void run() {
for (int i = 0; i < limit; i++) {
System.out.println(getName() + ": " + i);
}
}
}
// 使用
new PrintTask(100).start();
public class PrintRunnable implements Runnable {
private final int limit;
public PrintRunnable(int limit) {
this.limit = limit;
}
@Override
public void run() {
for (int i = 0; i < limit; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
// 使用:同一實例可給多線程,共享狀態
PrintRunnable task = new PrintRunnable(100);
new Thread(task, "Thread-A").start();
new Thread(task, "Thread-B").start();
public class SumCallable implements Callable<Integer> {
private final int n;
public SumCallable(int n) {
this.n = n;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
}
return sum;
}
}
// 使用
Callable<Integer> callable = new SumCallable(100);
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask, "CalcThread").start();
try {
Integer result = futureTask.get(); // 阻塞獲取結果
System.out.println("Sum: " + result);
} catch (InterruptedException | ExecutionException e) {
// 處理中斷或任務內部異常
e.printStackTrace();
}
手動 new Thread() 的弊端:頻繁創建銷毀開銷大、無法控制併發數、異常處理分散。
// 1. 固定大小線程池(CPU 密集型推薦)
ExecutorService fixedPool = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors()
);
// 2. 緩存線程池(IO 密集型、任務短小)
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 3. 單線程串行(保證順序)
ExecutorService singlePool = Executors.newSingleThreadExecutor();
// 4. 定時/周期任務
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2);
// 提交 Runnable
fixedPool.execute(() -> System.out.println("Runnable task"));
// 提交 Callable,獲取 Future
Future<String> future = fixedPool.submit(() -> {
Thread.sleep(1000);
return "Result";
});
try {
System.out.println(future.get(2, TimeUnit.SECONDS));
} catch (TimeoutException e) {
future.cancel(true); // 超時取消
}
// 關閉線程池(優雅關閉)
fixedPool.shutdown();
try {
if (!fixedPool.awaitTermination(60, TimeUnit.SECONDS)) {
fixedPool.shutdownNow(); // 強制關閉
}
} catch (InterruptedException e) {
fixedPool.shutdownNow();
Thread.currentThread().interrupt();
}
// 阿里巴巴開發手冊強制要求:生產環境不允許使用 Executors 創建線程池
ThreadPoolExecutor pool = new ThreadPoolExecutor(
4, // corePoolSize
8, // maximumPoolSize
60L, TimeUnit.SECONDS, // keepAliveTime
new LinkedBlockingQueue<>(1000), // 有界隊列,防止 OOM
new ThreadFactoryBuilder().setNameFormat("order-process-%d").build(), // 有意義線程名
new ThreadPoolExecutor.AbortPolicy() // 拒絕策略:拋異常,便於監控報警
);
關鍵參數解釋:
corePoolSize:常駐線程數,即使閒置也不銷毀(除非 allowCoreThreadTimeOut(true))maximumPoolSize:隊列滿後最大擴容線程數workQueue:必須有界,無界隊列會導致 maximumPoolSize 失效,直接 OOMThreadFactory:命名規範如 biz-module-%d,排查堆棧神器RejectedExecutionHandler:AbortPolicy 拋異常最利於發現問題;CallerRunsPolicy 由調用線程執行,適合不允許丟失任務場景
submit(task)
│
▼
corePoolSize 未滿? ──是──▶ 創建核心線程執行
│ 否
▼
workQueue 未滿? ──是──▶ 入隊等待
│ 否
▼
maximumPoolSize 未滿? ──是──▶ 創建非核心線程執行
│ 否
▼
執行 RejectedExecutionHandler 拒絕策略
future.get() 捕獲 ExecutionException 或使用 Thread.setDefaultUncaughtExceptionHandlerremove()業務代碼首選 Runnable + 自定義線程池;需返回值用 Callable + Future;定時任務用 ScheduledExecutorService。拒絕 new Thread()、拒絕 Executors 預設工廠、拒絕無界隊列,這是高併發穩定系統的基石。