public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
| 參數 | 含義 | 建議 |
|---|---|---|
| corePoolSize | 核心線程數(常駐) | CPU 密集型:N+1;IO 密集型:2*N(N=CPU 核心數) |
| maximumPoolSize | 最大線程數 | 根據隊列類型決定:有界隊列可設大;無界隊列無效 |
| keepAliveTime | 非核心線程空閒存活時間 | 60s~300s,避免頻繁伸縮 |
| unit | 時間單位 | TimeUnit.SECONDS |
| workQueue | 任務隊列 | 關鍵選型見下表 |
| threadFactory | 線程工廠 | 命名前綴(如 "order-process-"),便於排查;可設置守護線程 |
| handler | 拒絕策略 | 四大內置策略見下文 |
| 隊列類型 | 特點 | 適用場景 | maximumPoolSize 效力 |
|---|---|---|---|
ArrayBlockingQueue | 有界數組,FIFO | 穩定延遲、防 OOM、需拒絕策略配合 | ✅ 隊列滿才擴容到 max |
LinkedBlockingQueue | 無界鏈表(默認 Integer.MAX_VALUE) | 任務量可控、優先保證不丟任務 | ❌ 永遠不會擴容到 max |
SynchronousQueue | 零容量,直接移交 | 高吞吐、快速失敗、需足夠 max 線程 | ✅ 必須配大 max |
PriorityBlockingQueue | 優先級隊列 | 任務有輕重緩急 | ✅ |
DelayQueue | 延遲隊列 | 定時/重試任務 | ✅ |
⚠️ 阿里規約:禁止使用 Executors 默認工廠(FixedThreadPool/单线程池用無界隊列 OOM 風險;CachedThreadPool 無界線程 OOM 風險),**必須自定義 ThreadPoolExecutor 明確參數**。
AbortPolicy(默認):拋 RejectedExecutionException,快速失敗。CallerRunsPolicy:由調用線程(提交任務的線程)執行任務,**天然降流削峰**,適合不允許丟失任務、任務耗時短的場景。DiscardPolicy:默默丟棄任務,**極其危險**,慎用。DiscardOldestPolicy:丟棄隊列頭部最老任務,嘗試重新提交,可能丟棄重要任務。自定義策略:記錄日誌、發送告警、持久化到 DB/消息隊列、降級處理(返回默認值/熔斷)。
thread-pool:
core-size: 10
max-size: 50
queue-capacity: 200
keep-alive: 60s
name-prefix: "biz-async-"
@Configuration
@ConfigurationProperties(prefix = "thread-pool")
public class ThreadPoolConfig {
private int coreSize, maxSize, queueCapacity;
private Duration keepAlive;
private String namePrefix;
// getter/setter
@Bean("bizExecutor")
public ThreadPoolTaskExecutor bizExecutor() {
ThreadPoolTaskExecutor exec = new ThreadPoolTaskExecutor();
exec.setCorePoolSize(coreSize);
exec.setMaxPoolSize(maxSize);
exec.setQueueCapacity(queueCapacity);
exec.setKeepAliveSeconds((int) keepAlive.getSeconds());
exec.setThreadNamePrefix(namePrefix);
exec.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
exec.setWaitForTasksToCompleteOnShutdown(true); // 優雅關機
exec.setAwaitTerminationSeconds(30);
exec.initialize();
return exec;
}
}
@Autowired @Qualifier("bizExecutor") ThreadPoolTaskExecutor executor;
public void asyncProcess(Order order) {
executor.submit(() -> orderService.process(order));
}
// 或 @Async("bizExecutor")
@Async("bizExecutor")
public CompletableFuture calc(Param p) { ... }
| 坑 | 後果 | 解決方案 |
|---|---|---|
| 任務執行拋異常未捕獲 | 線程死亡,池縮容,任務靜默丟失 | 任務代碼包 try-catch;或自定義 ThreadFactory 設置 UncaughtExceptionHandler 記錄日誌、告警 |
| 提交長耗時阻塞任務 (HTTP調用、DB查詢) | 核心線程耗盡,新任務進隊列,延遲飆升 | 區分 CPU/IO 任務用隔離線程池;IO 任務配大隊列、大 max;考慮虛擬線程 (JDK 21) |
| 隊列無界 + 任務產生 > 消費 | OOM | 強制有界隊列 + 拒絕策略 + 監控告警(隊列積壓 > 閾值報警) |
| ThreadLocal 內存洩漏 | 線程復用導致 ThreadLocal 不釋放 | 用完 remove();或用 TransmittableThreadLocal (阿里開源) 支持線程池傳遞 |
| 關機不優雅 | 隊列任務丟失 | shutdown() + awaitTermination();Spring waitForTasksToCompleteOnShutdown=true |
| 死鎖:任務互相等待對方結果 | 線程池凍結 | 避免同步等待異步結果;用 CompletableFuture 串聯;或單獨池跑依賴任務 |
// 輕量級、無池化開銷、適合高並發 IO
ExecutorService virtualExecutor = Executors.newVirtualThreadPerTaskExecutor();
virtualExecutor.submit(() -> { blockingIoCall(); });
虛擬線程讓「一請求一線程」成為可能,徹底解決 IO 密集型線程池調優難題,**新項目優先評估 JDK 21+ 虛擬線程方案**。
線程池是並發編程的「心臟」。**拒絕 Executors、拒絕無界隊列、拒絕默認拒絕策略**。按業務隔離池、配置有界隊列、CallerRuns 削峰、監控全鏈路、優雅關機、JDK 21 拥抱虛擬線程 —— 這才是生產級姿勢。