最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深度解析Spring Boot @Async 正在榨干服務(wù)器資源

 更新時間:2026年02月27日 15:15:30   作者:Omari7  
這篇文章主要介紹了Spring Boot @Async 正在榨干服務(wù)器資源,我們就來徹底搞懂 @Async 背后的線程池,并學會如何像個老手一樣駕馭它,讓你的應(yīng)用在高并發(fā)下穩(wěn)如泰山,需要的朋友可以參考下

“服務(wù)又掛了?日志里全是 OutOfMemoryError: unable to create new native thread!”

你是否也曾深夜被這樣的報警驚醒?明明只是一個簡單的異步處理,用 @Async 注解輕輕一標,本地測試跑得飛快,一到高并發(fā)壓測就瞬間“猝死”。這幾乎是每個從初級走向中級的 Java 開發(fā)者都會踩的坑。

問題出在哪里?出在你以為 @Async 是“銀彈”,但實際上,你只是把它當成了一把沒加防護的“電鋸”在用。今天,我們就來徹底搞懂 @Async 背后的線程池,并學會如何像個老手一樣駕馭它,讓你的應(yīng)用在高并發(fā)下穩(wěn)如泰山。

核心概念拆解:把線程池當成一個“智慧廚房”

忘掉那些枯燥的 API 定義,我們用一個更形象的方式來理解線程池的核心思想。

想象一下,你開了一家生意火爆的餐廳。

  • 請求 (Request):源源不斷進店點餐的顧客。
  • 線程 (Thread):負責炒菜的廚師。

方案一:裸奔模式 (不使用線程池) 每來一位顧客,你就臨時去人才市場招一位新廚師。顧客少的時候還行,一旦到了飯點高峰期,幾百個顧客同時涌入,你的小廚房瞬間塞滿了臨時廚師,亂作一團,最終廚房(服務(wù)器內(nèi)存)被擠爆,餐廳(服務(wù))直接關(guān)門大吉。這就是 unable to create new native thread 的本質(zhì)——系統(tǒng)資源被無限創(chuàng)建的線程耗盡了。

方案二:智慧廚房模式 (使用線程池) 你學聰明了,建立了一個專業(yè)的廚師團隊(線程池)。

  1. 核心廚師 (corePoolSize):你有 5 位正式廚師,他們是廚房的中堅力量,時刻準備接單。
  2. 等餐區(qū) (workQueue):當 5 位廚師都在忙時,新來的訂單會先放到一個等餐區(qū)(任務(wù)隊列)排隊。
  3. 臨時工 (maximumPoolSize):如果等餐區(qū)的訂單也排滿了(比如超過 100 單),說明生意實在太火爆了。你決定臨時再請 3 位廚師來幫忙,這樣廚房最多就有 8 位廚師。
  4. 拒絕策略 (RejectedExecutionHandler):如果 8 位廚師全在忙,等餐區(qū)也滿了,再有新顧客來,服務(wù)員(拒絕策略)就會禮貌地告訴他:“抱歉,今天太忙了,您稍后再來吧。” 而不是讓顧客無止境地等下去,最終導致體驗崩潰。
  5. 臨時工的補貼 (keepAliveTime):高峰期過后,那 3 位臨時工如果連續(xù) 1 分鐘都沒接到新活,你就會讓他們下班,以節(jié)省成本(釋放空閑線程資源),只保留 5 位核心廚師。

看到了嗎?一個設(shè)計良好的線程池,就像一個管理有序的智慧廚房,它通過復用、排隊限流,確保了在任何客流量下,廚房都能高效、穩(wěn)定地運轉(zhuǎn),而不是無限擴張導致崩潰。

實戰(zhàn)落地:在 Spring Boot 中正確“馴服”@Async

光說不練假把式。我們來看如何在 Spring Boot 項目中,從“裸奔”模式進化到“精細化”管理模式。

1. 依賴(Maven)

你只需要 Spring Boot 的 Web 啟動器,@Async 的支持是內(nèi)置的。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.7.5</version> <!-- 請根據(jù)你的項目選擇合適的版本 -->
</dependency>

2. 啟用異步功能

在你的主啟動類上添加 @EnableAsync 注解。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync // 開啟異步任務(wù)支持
public class HighConcurrencyApplication {
    public static void main(String[] args) {
        SpringApplication.run(HighConcurrencyApplication.class, args);
    }
}

3. 錯誤的用法(裸奔的@Async)

很多新手會直接在一個 Service 方法上標注 @Async,就像這樣:

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
    @Async // 警告:這是默認配置,高并發(fā)下極度危險!
    public void processOrder(String orderId) {
        // 模擬處理訂單的耗時操作
        System.out.println(Thread.currentThread().getName() + " 開始處理訂單: " + orderId);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 訂單處理完成: " + orderId);
    }
}

為什么危險? 因為在沒有自定義線程池的情況下,Spring Boot 會使用一個 SimpleAsyncTaskExecutor。這個執(zhí)行器不會復用線程,每次調(diào)用都會創(chuàng)建一個新線程。這和我們“智慧廚房”的反面教材——方案一,一模一樣。

4. 正確的姿勢:自定義線程池

我們需要創(chuàng)建一個配置類,來定義我們自己的“智慧廚房”。

ThreadPoolConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class ThreadPoolConfig {
    // Bean 的名稱,我們將在 @Async 注解中引用它
    public static final String ASYNC_EXECUTOR_NAME = "myAsyncExecutor";
    @Bean(name = ASYNC_EXECUTOR_NAME)
    public Executor myAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心廚師數(shù)量:根據(jù)CPU核心數(shù)動態(tài)計算
        int corePoolSize = Runtime.getRuntime().availableProcessors();
        executor.setCorePoolSize(corePoolSize); 
        // 最大廚師數(shù)量:通常是核心數(shù)的2-3倍
        executor.setMaxPoolSize(corePoolSize * 2);
        // 等餐區(qū)容量
        executor.setQueueCapacity(100); 
        // 臨時工的存活時間
        executor.setKeepAliveSeconds(60); 
        // 給廚師起個好名字,方便排查問題
        executor.setThreadNamePrefix("My-Async-"); 
        // 拒絕策略:讓調(diào)用者自己處理,這是最穩(wěn)妥的方式
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize();
        return executor;
    }
}

application.yml (推薦)

為了靈活性,最好將核心參數(shù)配置在 application.yml 中。

myapp:
  async:
    core-pool-size: 8
    max-pool-size: 16
    queue-capacity: 200
    keep-alive-seconds: 60

然后在配置類中通過 @Value 注入這些值。

5. 在業(yè)務(wù)代碼中指定線程池

現(xiàn)在,讓我們的 OrderService 使用新定義的“智慧廚房”。

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.yourpackage.config.ThreadPoolConfig; // 引入你的配置類
@Service
public class OrderService {
    // 通過 value 屬性指定要使用的線程池 Bean 名稱
    @Async(ThreadPoolConfig.ASYNC_EXECUTOR_NAME)
    public void processOrder(String orderId) {
        // ... 業(yè)務(wù)邏輯不變 ...
        System.out.println("使用自定義線程池 [" + Thread.currentThread().getName() + "] 開始處理訂單: " + orderId);
        // ...
    }
}

現(xiàn)在,所有的異步訂單處理任務(wù)都會被提交到我們精心設(shè)計的 myAsyncExecutor 線程池中,再也不怕野線程滿天飛了。

避坑指南:生產(chǎn)環(huán)境的“秘密”

  • 小心“無底洞”隊列:千萬不要將 queueCapacity 設(shè)置得過大,或者使用 Executors.newFixedThreadPool(),它內(nèi)部使用的是無界的 LinkedBlockingQueue。在高并發(fā)下,如果任務(wù)處理速度跟不上生產(chǎn)速度,會導致請求在隊列中大量堆積,最終引發(fā) OOM。有限的隊列是保護系統(tǒng)的第一道防線。
  • 優(yōu)雅停機很重要:Spring Boot 默認會等待異步任務(wù)執(zhí)行完畢再關(guān)閉應(yīng)用。但你需要通過 spring.task.execution.shutdown.await-termination=truespring.task.execution.shutdown.await-termination-period 來確保有足夠的時間讓任務(wù)完成,防止服務(wù)關(guān)閉時丟失正在處理的數(shù)據(jù)。
  • 別忘了線程上下文:如果你在異步方法中需要獲取 RequestContext(如用戶信息、TraceID),默認情況下是拿不到的。你需要自己處理上下文的傳遞,或者使用像 TransmittableThreadLocal 這樣的庫來自動完成。這又是另一個深坑,值得單獨寫一篇文章。

總結(jié)與升華

我們今天從一個常見的 OOM 慘案出發(fā),通過一個“智慧廚房”的比喻,徹底理解了線程池的工作原理。核心的收獲是:

永遠不要在生產(chǎn)環(huán)境中使用默認的 @Async,必須為其提供一個經(jīng)過精細化配置的自定義線程池。

這不僅是代碼技巧,更是一種對系統(tǒng)負責的架構(gòu)思維。我們從“能用”走向了“可靠、可控”。

最后,留一個思考題:我們今天討論的都是單個應(yīng)用內(nèi)的線程池。如果我們的系統(tǒng)是分布式的微服務(wù)架構(gòu),一個請求需要跨越多個服務(wù),我們又該如何控制整個鏈路的并發(fā)和資源,防止上游的流量洪峰打垮下游所有服務(wù)呢?

到此這篇關(guān)于Spring Boot @Async 正在榨干服務(wù)器資源的文章就介紹到這了,更多相關(guān)Spring Boot @Async服務(wù)器資源內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

且末县| 武义县| 贵德县| 馆陶县| 安丘市| 都匀市| 当涂县| 永吉县| 潢川县| 大渡口区| 商丘市| 望江县| 嘉义市| 营山县| 漠河县| 永康市| 宁津县| 九龙城区| 营口市| 苏州市| 巫溪县| 拉孜县| 秭归县| 绥中县| 新野县| 梅州市| 霍林郭勒市| 宣化县| 云霄县| 青州市| 迁安市| 丰原市| 蒙山县| 哈尔滨市| 麻栗坡县| 平乡县| 三都| 漯河市| 辽中县| 乃东县| 江西省|