為什麼需要調優線程池?
線程池是 Java Web 容器(Tomcat、Jetty、Undertow)處理 HTTP 請求的核心。配置不當導致:
- 過小:請求排隊、響應超時、吞吐量低
- 過大:CPU 上下文切換頻繁、內存溢出、GC 停頓
- 拒絕策略錯誤:丟棄重要請求、調用者線程被阻塞
線程池核心參數(ThreadPoolExecutor)
public ThreadPoolExecutor(
int corePoolSize, // 核心線程數(常駐)
int maximumPoolSize, // 最大線程數(峰值)
long keepAliveTime, // 非核心線程存活時間
TimeUnit unit,
BlockingQueue<Runnable> workQueue, // 任務隊列
ThreadFactory threadFactory,
RejectedExecutionHandler handler // 拒絕策略
)
參數調優黃金法則
1. 核心線程數
- CPU 密集型:
core = CPU 核心數 + 1(減少上下文切換)
- IO 密集型:
core = CPU 核心數 * (1 + 平均等待時間 / 平均工作時間),經驗值 2 * CPU 核心數
2. 隊列選擇
| 隊列類型 | 特點 | 適用場景 |
| ArrayBlockingQueue | 有界數組,FIFO | 穩定吞吐、需防止 OOM |
| LinkedBlockingQueue | 無界鏈表(默認 Integer.MAX_VALUE) | 任務輕量、峰值可控,**生產慎用** |
| SynchronousQueue | 無容量,直接移交 | 高響應、配合 maximumPoolSize 彈性擴縮 |
| PriorityBlockingQueue | 優先級排序 | 任務有輕重緩急 |
建議:Web 容器常用有界 ArrayBlockingQueue + 拒絕策略,防止突發流量撐爆內存。
3. 拒絕策略
AbortPolicy(默認):拋出異常,調用者感知失敗
CallerRunsPolicy:調用者線程執行任務,**天然背壓**,適合不想丟任務的場景
DiscardOldestPolicy:丟棄隊頭最舊任務
DiscardPolicy:靜默丟棄,**不可取**
Tomcat 線程池實戰配置
<!-- server.xml -->
<Executor name="tomcatThreadPool" namePrefix="http-nio-"
corePoolSize="200"
maxPoolSize="800"
keepAliveTime="60000"
queueCapacity="500"
minSpareThreads="50"
maxIdleTime="60000"
prestartminSpareThreads="true"
threadPriority="5"/>
<Connector executor="tomcatThreadPool"
port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
maxConnections="10000"
acceptCount="100"
connectionTimeout="20000"
compression="on"
compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/json"/>
業務線程池隔離模式
不要所有業務共用一個池,按業務域隔離:
@Configuration
public class ThreadPoolConfig {
@Bean("orderExecutor")
public ThreadPoolTaskExecutor orderExecutor() {
ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
ex.setCorePoolSize(50); ex.setMaxPoolSize(100);
ex.setQueueCapacity(200);
ex.setThreadNamePrefix("order-");
ex.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
ex.initialize(); return ex;
}
@Bean("reportExecutor")
public ThreadPoolTaskExecutor reportExecutor() {
ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
ex.setCorePoolSize(10); ex.setMaxPoolSize(20);
ex.setQueueCapacity(500); // 報表任務耗時長,隊列可大
ex.setThreadNamePrefix("report-");
ex.initialize(); return ex;
}
}
監控與動態調優
- 關鍵指標:
activeCount、queue.size()、completedTaskCount、rejectCount
- 暴露 Endpoint:Spring Boot Actuator
/actuator/metrics/tomcat.threads.*、自定義 /actuator/threadpools
- 動態調整:結合 Nacos/Apollo 配置中心,運行期修改
corePoolSize/maxPoolSize/queueCapacity
- 壓測驗證:JMeter 持續施壓,觀察隊列積壓、拒絕率、GC 頻率、CPU 使用率
避坑指南
- ❌ 使用
Executors.xxx 創建池(無界隊列、固定大小、無命名)
- ❌ 所有業務共用
commonThreadPool
- ❌
keepAliveTime 設置過短導致頻繁創建銷毀
- ✅ 顯式命名線程前綴,便於日誌排查
- ✅ 核心業務配置
CallerRunsPolicy 保護下游
- ✅ 定期導出線程快照 (
jstack) 分析線程狀態
- 上一篇文章: Java 實現 RSA 與 DSA 數字簽名算法完整指南
- 下一篇文章: Struts2 過濾器與攔截器差異深度解析
Copyright ©
程式碼之家 All Rights Reserved