| 工廠方法 | 底層實現 | 核心參數 | 適用場景 | 風險 |
newFixedThreadPool(n) | ThreadPoolExecutor | core=max=n, queue=LinkedBlockingQueue(無界) | 長期任務、固定併發、CPU 密集 | 隊列無界 → OOM 風險 |
newCachedThreadPool() | ThreadPoolExecutor | core=0, max=Integer.MAX_VALUE, queue=SynchronousQueue, keepAlive=60s | 短期異步任務、IO 密集、數量不定 | 無界線程 → OOM 風險 |
newSingleThreadExecutor() | FinalizableDelegatedExecutorService | core=max=1, queue=LinkedBlockingQueue(無界) | 串行任務、順序執行、UI 事件循環 | 單點瓶頸、隊列無界 |
newScheduledThreadPool(n) | ScheduledThreadPoolExecutor | core=n, max=Integer.MAX_VALUE, queue=DelayedWorkQueue | 定時任務、周期任務、延遲執行 | 非核心線程無界 |
| 策略 | 行為 | 適用場景 |
| AbortPolicy (默認) | 拋 RejectedExecutionException | 關鍵業務、必須感知拒絕 |
| CallerRunsPolicy | 調用者線程執行任務 | 自然限流、不丟任務、降低提交速度 |
| DiscardPolicy | 靜默丟棄 | 非關鍵、可丟失 (如日志、監控) |
| DiscardOldestPolicy | 丟棄隊首最老任務,重試提交 | 優先處理新任務、隊列有界 |
| 自定義 | 持久化到 DB/隊列、告警、降級 | 業務級拒絕處理 |
生產環境自定義線程池最佳實踐
@Configuration
public class ThreadPoolConfig {
@Bean("businessExecutor")
public ThreadPoolTaskExecutor businessExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心參數
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(200); // 有界隊列!
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("biz-");
executor.setThreadFactory(new CustomThreadFactory("biz-"));
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true); // 優雅關閉
executor.setAwaitTerminationSeconds(30);
executor.initialize();
return executor;
}
@Bean("ioExecutor")
public ThreadPoolTaskExecutor ioExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(500);
executor.setKeepAliveSeconds(120);
executor.setThreadNamePrefix("io-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
@Bean("scheduledExecutor")
public ThreadPoolTaskScheduler scheduledExecutor() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5);
scheduler.setThreadNamePrefix("sched-");
scheduler.setWaitForTasksToCompleteOnShutdown(true);
scheduler.setAwaitTerminationSeconds(60);
return scheduler;
}
}
// 自定義線程工廠:命名、非守護、異常處理
public class CustomThreadFactory implements ThreadFactory {
private final AtomicInteger index = new AtomicInteger(0);
private final String prefix;
public CustomThreadFactory(String prefix) { this.prefix = prefix; }
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(() -> {
try { r.run(); }
catch (Throwable e) {
// 全局異常處理、上報監控
log.error("線程池任務異常: {}", prefix, e);
}
}, prefix + index.incrementAndGet());
t.setDaemon(false); // 非守護,防止 JVM 過早退出
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
參數計算公式
| 任務類型 | 核心線程數 | 最大線程數 | 隊列類型 |
| CPU 密集 (計算、加密、壓縮) | CPU 核心數 + 1 | CPU 核心數 * 2 | ArrayBlockingQueue (有界) |
| IO 密集 (DB、HTTP、文件、緩存) | CPU 核心數 * 2 | CPU 核心數 * 4 (或更高) | LinkedBlockingQueue (有界) |
| 混合型 | 根據業務壓測調整 | 同上 | 優先級隊列或分離池 |
// 獲取 CPU 核心數
int cores = Runtime.getRuntime().availableProcessors();
// 典型配置
int cpuCore = cores + 1;
int ioCore = cores * 2;
int cpuMax = cores * 2;
int ioMax = cores * 4;
監控與運維
p.getQueue().size())
.tag("pool", name).register(registry);
Gauge.builder("threadpool.completed", pool, ThreadPoolExecutor::getCompletedTaskCount)
.tag("pool", name).register(registry);
Gauge.builder("threadpool.rejected", pool, p ->
((ThreadPoolTaskExecutor)executors.get(name)).getThreadPoolExecutor().getRejectedExecutionHandler().toString())
.tag("pool", name).register(registry);
}
}
}
優雅關閉
@PreDestroy
public void shutdown() {
// 1. 停止接受新任務
executor.shutdown();
// 2. 等待現有任務完成 (超時則強制關閉)
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
List<Runnable> remaining = executor.shutdownNow(); // 嘗試中斷執行中任務
log.warn("線程池強制關閉,剩余任務數: {}", remaining.size());
// 持久化剩余任務或告警
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
常見誤區與避坑
| 誤區 | 後果 | 正確做法 |
| 直接使用 Executors.xxx | 無界隊列/線程 → OOM、無法自定義參數 | 自定義 ThreadPoolExecutor、Spring ThreadPoolTaskExecutor |
| 核心=最大、無界隊列 | 峰值時任務堆積、內存飆升、響應超時 | 有界隊列 + 非核心線程緩衝峰值 |
| 線程名稱默認 pool-1-thread-1 | 排查困難、無法關聯業務 | ThreadNamePrefix 設置業務前綴 |
| 未處理任務異常 | 線程意外終止、池縮容、任務靜默失敗 | ThreadFactory 包裝 try-catch、全局異常處理器 |
| 關閉不等待任務完成 | 數據不一致、事務未提交、資源洩漏 | shutdown() + awaitTermination() + 持久化剩余 |
| 所有業務共用一個池 | 相互干擾、核心業務被非核心擠佔 | 業務隔離:核心/IO/定時/批處理分離池 |
新特性:Virtual Threads (JDK 21+)
// 虛擬線程池:輕量級、百萬級併發、無需調優參數
ExecutorService virtualExecutor = Executors.newVirtualThreadPerTaskExecutor();
@Configuration
public class VirtualThreadConfig {
@Bean
public ExecutorService virtualExecutor() {
return Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory());
}
}
// Spring Boot 3.2+ 自動配置
spring:
threads:
virtual:
enabled: true
線程池是 Java 並發編程的核心基礎設施。生產環境嚴禁直接使用 Executors 預定義池,必須根據業務類型 (CPU/IO/混合)、流量特點 (峰值/平均)、SLA 要求 (超時/丟包率) 精細配置七大參數,並建立完善的監控、告警、優雅關閉機制。JDK 21 虛擬線程將徹底改寫高併發 IO 密集型應用的線程模型,值得持續關注。
- 上一篇文章: Java 讀取文本文件最佳實踐:BufferedReader、編碼處理與資源管理
- 下一篇文章: Spring 整合 WebSocket 實戰(上):配置、握手攔截與會話管理
Copyright ©
程式碼之家 All Rights Reserved