Java 線程池預(yù)熱(Warm-up)實戰(zhàn)
一、什么是線程池預(yù)熱?
線程池第一次執(zhí)行任務(wù)時會:
- 創(chuàng)建核心線程
- 加載類
- JIT 編譯熱點方法
- 建立資源連接(DB / Redis / RPC)
這些都需要時間,因此第一次執(zhí)行任務(wù)一般比后續(xù)慢很多。
線程池預(yù)熱(warm-up)就是:
? 在系統(tǒng)啟動時提前創(chuàng)建線程
? 并讓線程執(zhí)行一次輕量任務(wù)
使其進入 已加載、已編譯、已就緒 的狀態(tài)。
二、Demo:不開啟預(yù)熱 vs 開啟預(yù)熱
我們做兩個測試:
- 未預(yù)熱 → 首次任務(wù)延遲明顯更高
- 預(yù)熱后 → 首次任務(wù)也能保持正常速度
三、測試代碼
以下代碼包含兩個方法:
① testWithoutWarmUp() 未預(yù)熱
② testWithWarmUp() 已預(yù)熱
完整可運行 Demo:ThreadPoolWarmUpDemo.java
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class ThreadPoolWarmUpDemo {
public static void main(String[] args) throws Exception {
System.out.println("========== 未開啟預(yù)熱,測試開始 ==========");
testWithoutWarmUp();
System.out.println("\n========== 開啟預(yù)熱后,測試開始 ==========");
testWithWarmUp();
}
/** 用于模擬“第一次慢,后面快” */
private static final AtomicBoolean firstRun = new AtomicBoolean(true);
/** 模擬核心業(yè)務(wù)邏輯 */
private static void mockBizWork() {
try {
if (firstRun.compareAndSet(true, false)) {
// 只在第一次執(zhí)行時慢
Thread.sleep(50);
} else {
// 后續(xù)任務(wù)很快
Thread.sleep(2);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
/** 創(chuàng)建一個全新的線程池(關(guān)鍵) */
private static ThreadPoolExecutor newExecutor() {
return new ThreadPoolExecutor(
4, 4,
60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>()
);
}
/** 未開啟線程池預(yù)熱 */
public static void testWithoutWarmUp() throws Exception {
ThreadPoolExecutor executor = newExecutor();
firstRun.set(true);
long start = System.currentTimeMillis();
Future<Long> future = executor.submit(() -> {
long s = System.currentTimeMillis();
mockBizWork();
return System.currentTimeMillis() - s;
});
long firstCost = future.get();
long totalCost = System.currentTimeMillis() - start;
System.out.println("第一次任務(wù)耗時 = " + firstCost + " ms");
System.out.println("整體耗時(含線程創(chuàng)建)= " + totalCost + " ms");
executor.shutdown();
}
/** 開啟預(yù)熱 */
public static void testWithWarmUp() throws Exception {
ThreadPoolExecutor executor = newExecutor();
firstRun.set(true);
System.out.println(">>> 開始預(yù)熱核心線程...");
executor.prestartAllCoreThreads();
// 預(yù)熱任務(wù):吃掉“第一次慢”
for (int i = 0; i < 4; i++) {
executor.submit(ThreadPoolWarmUpDemo::mockBizWork).get();
}
System.out.println(">>> 預(yù)熱完成!");
long start = System.currentTimeMillis();
Future<Long> future = executor.submit(() -> {
long s = System.currentTimeMillis();
mockBizWork();
return System.currentTimeMillis() - s;
});
long cost = future.get();
long totalCost = System.currentTimeMillis() - start;
System.out.println("第一次任務(wù)耗時(已預(yù)熱)= " + cost + " ms");
System.out.println("整體耗時(線程已就緒)= " + totalCost + " ms");
executor.shutdown();
}
}

四、對比圖(示例)
| 場景 | 首次任務(wù)耗時 | 備注 |
|---|---|---|
| ?? 未預(yù)熱 | 55 ms | 包含線程創(chuàng)建、類加載等 |
| ?? 已預(yù)熱 | 3 ms | 線程已創(chuàng)建、JIT 已編譯,幾乎“秒回” |
五、什么時候必須使用線程池預(yù)熱?
以下場景建議開啟:
? 高并發(fā)系統(tǒng)(交易、支付、秒殺)
首個請求慢會直接影響用戶體驗和系統(tǒng)穩(wěn)定性。
? 微服務(wù)自動擴容(K8S / Spring Cloud)
Pod 剛拉起來就被流量打滿,如果沒預(yù)熱會導(dǎo)致:
- 錯誤率突然增加
- P99 延遲飆升
- 下游熔斷
? 接口對響應(yīng)時間敏感(推薦、風(fēng)控、廣告)
冷啟動會影響模型推理鏈路整體延遲。
六、總結(jié)
線程池預(yù)熱很簡單,但效果極其明顯。
?? 不預(yù)熱 = 首次任務(wù)慢幾十毫秒
?? 預(yù)熱后 = 首次任務(wù)幾毫秒完成
通過:
executor.prestartAllCoreThreads(); executor.submit(warmTask);
即可大幅減少冷啟動延遲,保證服務(wù)穩(wěn)定性和低延遲能力。
到此這篇關(guān)于Java 線程池預(yù)熱(Warm-up)實戰(zhàn)的文章就介紹到這了,更多相關(guān)Java 線程池預(yù)熱內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中g(shù)etResourceAsStream用法分析
這篇文章主要介紹了Java中g(shù)etResourceAsStream用法,較為詳細的分析了getResourceAsStream的功能及用法,需要的朋友可以參考下2015-06-06
IntelliJ IDEA自定義代碼提示模板Live Templates的圖文教程
這篇文章主要介紹了IntelliJ IDEA自定義代碼提示模板Live Templates,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03
使用Java實現(xiàn)HTTP和HTTPS代理服務(wù)詳解
這篇文章主要為大家詳細介紹了如何使用Java實現(xiàn)HTTP和HTTPS代理服務(wù),文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-04-04
Windows系統(tǒng)下修改jar包中的依賴實現(xiàn)過程
本文介紹了如何在Windows下修改和升級Java項目中的JAR包依賴,首先,通過解壓原JAR包并替換指定的依賴JAR文件來實現(xiàn)升級,然后,使用命令重新打包JAR文件,整個過程包括解壓、替換和打包三個步驟,確保項目能夠正確引用更新的依賴2025-12-12
Mybatis通過攔截器實現(xiàn)單數(shù)據(jù)源內(nèi)多數(shù)據(jù)庫切換
這篇文章主要為大家詳細介紹了Mybatis如何通過攔截器實現(xiàn)單數(shù)據(jù)源內(nèi)多數(shù)據(jù)庫切換,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12

