前言
線程池是 Java 併發編程的核心基礎設施,解決「頻繁創建/銷毀線程開銷大」與「無限制創建導致 OOM」兩大痛點。本文深度解析 Executor 框架兩級調度模型、核心接口體系、ThreadPoolExecutor 七大參數、四大預定義池、Callable/Future 異步編程模式,並給出生產環境配置建議。
一、Executor 框架:兩級調度模型
- 上層(應用級): 應用將任務分解,由
Executor 映射為固定數量線程
- 下層(OS 級): 操作系統內核將線程映射到硬件 CPU
- HotSpot VM: Java 線程 1:1 映射本地 OS 線程
二、核心接口體系
Executor (根接口)
└─ execute(Runnable command) // 異步執行,無返回值
ExecutorService (繼承 Executor)
├─ submit(Callable) : Future // 支持返回值
├─ submit(Runnable) : Future>
├─ invokeAll / invokeAny // 批量任務
└─ shutdown() / shutdownNow() // 關閉控制
AbstractExecutorService (模板實現)
└─ ThreadPoolExecutor (核心實現)
└─ ScheduledThreadPoolExecutor (定時/周期任務)
三、ThreadPoolExecutor 七大參數全解
public ThreadPoolExecutor(
int corePoolSize, // 核心線程數(常駐)
int maximumPoolSize, // 最大線程數(峰值)
long keepAliveTime, // 非核心線程空閒存活時間
TimeUnit unit, // 時間單位
BlockingQueue workQueue, // 任務隊列
ThreadFactory threadFactory, // 線程工廠(命名、守護屬性)
RejectedExecutionHandler handler // 拒絕策略
)
工作流程:
- 線程數 < corePoolSize → 創建核心線程執行
- 線程數 ≥ corePoolSize → 任務入隊
workQueue
- 隊列滿 && 線程數 < maximumPoolSize → 創建非核心線程
- 隊列滿 && 線程數 = maximumPoolSize → 執行
handler 拒絕策略
四大拒絕策略:
AbortPolicy(默認):拋出 RejectedExecutionException
CallerRunsPolicy:調用者線程執行任務(緩衝壓力)
DiscardPolicy:靜默丟棄
DiscardOldestPolicy:丟棄隊列最舊任務,嘗試重新提交
四、Executors 工廠方法:三大預定義池(阿里規約不推薦直接使用)
| 方法 | core/max | 隊列 | 特點 | 風險 |
newSingleThreadExecutor() | 1 / 1 | LinkedBlockingQueue(無界) | 單線程串行,任務有序 | 隊列無界 → OOM |
newFixedThreadPool(n) | n / n | LinkedBlockingQueue(無界) | 固定並發度 | 隊列無界 → OOM |
newCachedThreadPool() | 0 / Integer.MAX_VALUE | SynchronousQueue(直接移交) | 彈性伸縮,60s 回收空閒 | 線程無界 → OOM |
newScheduledThreadPool(n) | n / n | DelayedWorkQueue | 定時/周期任務 | 同 FixedThreadPool |
生產環境建議:
// 自定義有界隊列 + 合理拒絕策略
ThreadPoolExecutor executor = new ThreadPoolExecutor(
核心數, 最大數, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(隊列容量),
new ThreadFactoryBuilder().setNameFormat("biz-%d").build(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
- CPU 密集型:核心數 = CPU 核心數 + 1
- IO 密集型:核心數 = CPU 核心數 × (1 + 平均等待時間/平均工作時間)
- 隊列容量:根據業務峰值 QPS × 最大可接受延遲估算
五、Callable / Future / FutureTask 異步編程
核心區別:
| 接口 | 方法 | 返回值 | 異常 |
| Runnable | run() | void | 不可拋受檢異常 |
| Callable | call() | V | 可拋異常 |
Future 主要方法:
get():阻塞獲取結果
get(timeout, unit):帶超時獲取
cancel(mayInterruptIfRunning):嘗試取消
isDone() / isCancelled():狀態查詢
FutureTask:
- 實現
RunnableFuture(繼承 Runnable + Future)
- 可作為任務提交給 Executor,也可直接用 Thread 運行
- 狀態機:NEW → COMPLETING → NORMAL/EXCEPTIONAL/CANCELLED
實戰模式:異步並行提升吞吐
// 場景:方法 A 耗時 10s,後續 20s 代碼中後 10s 依賴 A 結果
ExecutorService es = Executors.newSingleThreadExecutor();
Future future = es.submit(() -> {
Thread.sleep(10000);
return "A result";
});
// 先執行不依賴 A 的 10s 邏輯
doIndependentWork(10000);
// 獲取 A 結果(阻塞最多 10s,總耗時 20s 而非 30s)
String result = future.get();
doDependentWork(result);
es.shutdown();
六、CompletableFuture (Java 8+):更強大的異步編排
CompletableFuture.supplyAsync(() -> heavyCompute())
.thenApplyAsync(result -> transform(result))
.thenAcceptAsync(finalResult -> save(finalResult))
.exceptionally(ex -> { log.error(ex); return defaultVal; });
// 組合多個異步任務
CompletableFuture.allOf(f1, f2, f3).join();
CompletableFuture.anyOf(f1, f2).get();
支持鏈式調用、組合、異常處理、回調執行器指定,是現代 Java 異步編程首選。
七、線程池監控與調優關鍵指標
- activeCount:當前活躍線程數
- queue.size():待執行任務數
- completedTaskCount:已完成任務數
- reject 計數:拒絕次數(報警指標)
- 定期導出
ThreadPoolExecutor 狀態到監控系統(Prometheus/Grafana)
八、總結
- 理解兩級調度模型,區分線程池與線程組
- 掌握七大參數交互流程,拒絕用無界隊列/無界線程
- 優先使用自定義 ThreadPoolExecutor,配合有界隊列、CallerRunsPolicy
- 異步編程首選 CompletableFuture,避免 Future.get() 無限制阻塞
- 建立線程池監控體系,容量規劃基於壓測數據而非經驗拍腦袋
- 上一篇文章: MyBatis 框架從零搭建到 CRUD 實戰完整指南
- 下一篇文章: CentOS / Ubuntu 安裝 JDK 完全指南:四種方式任選
Copyright ©
程式碼之家 All Rights Reserved