Spring Boot 異步編程

文章目錄

    • 一、異步方法的使用
      • 1. 開啟異步支持
      • 2. 定義異步方法
      • 3. 調用異步方法
      • 踩坑記錄
      • 心得體會
    • 二、線程池配置
      • 1. 自定義線程池
      • 2. 使用自定義線程池
      • 踩坑記錄
      • 心得體會
    • 三、異步任務的監控與管理
      • 1. 日志記錄
      • 2. 異常處理
      • 3. 線程池監控
      • 踩坑記錄
      • 心得體會

在現代應用程序開發中,異步編程是提升系統性能和響應能力的重要手段。Spring Boot 提供了便捷的方式來實現異步編程,下面將詳細介紹異步方法的使用、線程池配置以及異步任務的監控與管理。

一、異步方法的使用

1. 開啟異步支持

在 Spring Boot 主應用類上添加 @EnableAsync 注解,開啟 Spring 的異步方法執行功能。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;@SpringBootApplication
@EnableAsync
public class AsyncApp {public static void main(String[] args) {SpringApplication.run(AsyncApp.class, args);}
}

2. 定義異步方法

在需要異步執行的方法上添加 @Async 注解。

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;import java.util.concurrent.CompletableFuture;@Service
public class AsyncService {@Asyncpublic CompletableFuture<String> asyncTask() {try {// 模擬耗時操作Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}return CompletableFuture.completedFuture("異步任務執行完成");}
}

3. 調用異步方法

在控制器或者其他服務類中注入包含異步方法的服務類,并調用異步方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;@RestController
public class AsyncController {@Autowiredprivate AsyncService asyncService;@GetMapping("/async")public String asyncCall() throws InterruptedException, ExecutionException {CompletableFuture<String> future = asyncService.asyncTask();// 可以在此處執行其他操作// 等待異步任務完成并獲取結果return future.get();}
}

踩坑記錄

  • 注解未生效:若 @EnableAsync 未添加到主應用類,或者異步方法所在類未被 Spring 管理(如未加 @Service 等注解),@Async 注解將不生效。此外,若在同一類中直接調用異步方法,而非通過 Spring 代理對象調用,也不會異步執行,因為 Spring 的 AOP 代理機制基于代理對象。
  • 返回值處理不當:有返回值的異步方法需用 CompletableFuture 包裝,若直接返回普通類型,調用 get() 方法獲取結果時可能阻塞或拋異常。

心得體會

要深刻理解 Spring 的 AOP 代理機制對 @Async 注解的影響,設計代碼時盡量通過依賴注入和代理對象調用異步方法。同時,對于有返回值的異步方法,務必使用 CompletableFuture 包裝,并妥善處理 get() 方法可能拋出的異常。

二、線程池配置

1. 自定義線程池

默認情況下,Spring Boot 使用簡單線程池執行異步任務。可通過創建配置類,使用 ThreadPoolTaskExecutor 自定義線程池。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;@Configuration
@EnableAsync
public class AsyncConfig {@Bean(name = "customAsyncExecutor")public Executor asyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();// 核心線程數executor.setCorePoolSize(5);// 最大線程數executor.setMaxPoolSize(10);// 隊列容量executor.setQueueCapacity(25);// 線程名前綴executor.setThreadNamePrefix("CustomAsyncThread-");// 線程池關閉時等待所有任務完成executor.setWaitForTasksToCompleteOnShutdown(true);// 等待任務完成的時間executor.setAwaitTerminationSeconds(60);// 初始化線程池executor.initialize();return executor;}
}

2. 使用自定義線程池

@Async 注解中指定使用自定義線程池的名稱。

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;import java.util.concurrent.CompletableFuture;@Service
public class AsyncService {@Async("customAsyncExecutor")public CompletableFuture<String> asyncTask() {try {Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}return CompletableFuture.completedFuture("異步任務執行完成");}
}

踩坑記錄

  • 參數設置不合理:核心線程數、最大線程數和隊列容量設置需根據業務場景調整。核心線程數過小,任務處理不及時;最大線程數過大,占用過多系統資源。隊列容量過小,新任務可能被拒絕;過大則可能導致任務堆積,影響系統響應時間。
  • 未正確初始化:配置線程池時,若忘記調用 executor.initialize() 方法,線程池可能無法正常工作,導致異步任務無法執行或執行過程中出現異常。

心得體會

配置線程池時,要充分考慮業務特點和系統資源情況。對于 I/O 密集型任務,可適當增大核心線程數;對于 CPU 密集型任務,核心線程數可相對較小。同時,務必確保調用 initialize() 方法初始化線程池。

三、異步任務的監控與管理

1. 日志記錄

在異步方法中添加日志記錄,跟蹤任務執行過程。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;import java.util.concurrent.CompletableFuture;@Service
public class AsyncService {private static final Logger logger = LoggerFactory.getLogger(AsyncService.class);@Async("customAsyncExecutor")public CompletableFuture<String> asyncTask() {logger.info("異步任務開始執行");try {Thread.sleep(2000);} catch (InterruptedException e) {logger.error("異步任務被中斷", e);Thread.currentThread().interrupt();}logger.info("異步任務執行完成");return CompletableFuture.completedFuture("異步任務執行完成");}
}

2. 異常處理

實現 AsyncUncaughtExceptionHandler 接口處理異步方法中拋出的未捕獲異常。

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;@Component
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {@Overridepublic void handleUncaughtException(Throwable throwable, Method method, Object... objects) {System.err.println("異步方法 " + method.getName() + " 拋出未捕獲異常");for (Object param : objects) {System.err.println("參數: " + param);}throwable.printStackTrace();}
}

在配置類中配置異常處理器:

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {@Bean(name = "customAsyncExecutor")public Executor asyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);executor.setThreadNamePrefix("CustomAsyncThread-");executor.setWaitForTasksToCompleteOnShutdown(true);executor.setAwaitTerminationSeconds(60);executor.initialize();return executor;}@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return new CustomAsyncExceptionHandler();}
}

3. 線程池監控

通過 ThreadPoolTaskExecutor 提供的方法獲取線程池狀態信息。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;@Service
public class ThreadPoolMonitorService {@Autowiredprivate ThreadPoolTaskExecutor customAsyncExecutor;public int getActiveThreadCount() {return customAsyncExecutor.getActiveCount();}public int getQueueSize() {return customAsyncExecutor.getThreadPoolExecutor().getQueue().size();}
}

踩坑記錄

  • 日志記錄不詳細:若日志信息不夠詳細,排查問題時會遇到困難。例如,只記錄任務開始和結束信息,未記錄關鍵步驟執行情況和異常信息,難以定位問題。
  • 異常處理不全面:實現 AsyncUncaughtExceptionHandler 接口時,若未全面處理異常,可能導致部分異常信息丟失。

心得體會

在異步方法中添加詳細日志記錄,包括任務開始、關鍵步驟、異常信息等,以便出現問題時能快速定位。實現異常處理器時,要盡可能全面記錄異常信息,為問題排查和修復提供有力支持。

總之,Spring Boot 異步編程能顯著提升系統性能和響應能力,但實際使用中需注意各種細節,避免踩坑。通過不斷實踐和總結經驗,才能更好地掌握異步編程技巧。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/897194.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/897194.shtml
英文地址,請注明出處:http://en.pswp.cn/news/897194.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

0.大模型開發知識點需求綜述

文章目錄 一、機器學習與深度學習基礎二、自然語言處理&#xff08;NLP&#xff09;基礎三、大模型架構四、訓練優化技術五、數據處理與預處理六、分布式訓練與并行化策略七、微調方法與參數高效微調八、訓練框架、工具與自動化流程九、評估與部署十、前沿技術與未來趨勢 已更新…

docker目錄掛載與卷映射的區別

在 Docker 中&#xff0c;目錄掛載&#xff08;Bind Mount&#xff09;和卷映射&#xff08;Volume Mount&#xff09;的命令語法差異主要體現在路徑格式上&#xff0c;具體表現為是否以斜杠&#xff08;/&#xff09;開頭。以下是兩者的核心區別及使用場景的總結&#xff1a; …

[Java基礎-線程篇]7_線程設計模式與總結

摘要&#xff1a;懶漢單例模式怎么變得線程安全&#xff1f;Master-Worker歸并模式&#xff0c;工作竊取算法。Java線程相關源碼使用了什么設計模式&#xff1f; 資料引用&#xff1a;《Java高并發核心編程卷2》 目錄 線程安全的單例模式 Master-Worker模式 工作竊取算法 …

在【k8s】中部署Jenkins的實踐指南

&#x1f407;明明跟你說過&#xff1a;個人主頁 &#x1f3c5;個人專欄&#xff1a;《Kubernetes航線圖&#xff1a;從船長到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目錄 一、引言 1、Jenkins簡介 2、k8s簡介 3、什么在…

代碼隨想錄算法營Day59 | 尋找存在的路徑, 冗余連接,冗余連接II

尋找存在的路徑 這題使用并查集即可。并查集加路徑壓縮。 #include <iostream> using namespace std; int find(int* father,int u){return father[u] u ? u : father[u] find(father,father[u]); }bool isSame(int* father,int u,int v){return find(father,u) fi…

正則表達式(2)匹配規則

正則表達式的匹配規則定義了如何識別字符串中的特定模式。這些規則包括字符類匹配、元字符匹配、數量詞、字符轉義和分組。 字符類匹配 字符類匹配允許你指定一個字符集合&#xff0c;并匹配該集合中的任意單個字符。這是通過方括號 [] 來實現的。 簡單字符類&#xff1a;[abc…

【QWEN】機器人控制器的控制周期越短精度越高嗎

好的&#xff0c;用戶問的是“機器人控制器的控制周期越短精度越高嗎”。我需要根據提供的知識庫內容來回答這個問題。首先&#xff0c;我得回憶一下知識庫里的相關信息。 知識庫里有幾篇相關的文章。比如&#xff0c;[3]提到控制周期越短&#xff0c;控制性能的上限越高&…

[總概]Vue2/3React Diff算法

根據搜索結果,大部分文檔都詳細描述了Vue的Diff算法原理、優化策略以及實現細節。例如,網頁1詳細介紹了Vue Diff算法的核心設計,包括雙端比較和key的作用;Vue3中的快速Diff算法; 通常,解釋一個算法可以從其基本原理、核心策略、優化手段、源碼實現以及應用場景等方面展開…

【MySQL_03】數據庫基本--核心概念

文章目錄 一、數據庫基礎1.1 數據庫基礎定義1.2 數據庫分類與典型產品1.3 數據庫模型1.4 數據庫層次結構1.5 數據庫核心機制1.6 數據表和視圖1.61 數據表&#xff08;Table&#xff09;1.62 視圖&#xff08;View&#xff09; 1.7 鍵類型1.8 MySQL數據類型1.9 數據庫范式化 二、…

FreeRTOS第16篇:FreeRTOS鏈表實現細節04_為什么FreeRTOS選擇“侵入式鏈表”

文/指尖動聽知識庫-星愿 文章為付費內容,商業行為,禁止私自轉載及抄襲,違者必究!!! 文章專欄:深入FreeRTOS內核:從原理到實戰的嵌入式開發指南 1 傳統鏈表 vs. 侵入式鏈表 在嵌入式系統中,內存和性能的優化至關重要。FreeRTOS選擇侵入式鏈表而非傳統鏈表,其背后是內…

STM32讀寫片內FLASH 筆記

文章目錄 前言STM32F105的內部ROM分布STM32F10x的閃存擦寫解鎖FPECMain FLASH 的編寫 main Flash的擦除注意點 前言 在通過OTA的方式對設備進行升級&#xff0c;若在使用內部FLASH裝載固件程序的方式下&#xff0c;需要擦寫 內部FLASH 從而實現把新的固件程序寫入到 內部FLASH…

Python爬蟲實戰:爬取財金網實時財經信息

注意:以下內容僅供技術研究,請遵守目標網站的robots.txt規定,控制請求頻率避免對目標服務器造成過大壓力! 一、引言 在當今數字化時代,互聯網數據呈爆炸式增長,其中蘊含著巨大的商業價值、研究價值和社會價值。從金融市場動態分析到行業趨勢研究,從輿情監測到學術信息收…

3.3.2 用仿真圖實現點燈效果

文章目錄 文章介紹Keil生成.hex代碼Proteus仿真圖中導入.hex代碼文件開始仿真 文章介紹 點燈之前需要準備好仿真圖keil代碼 仿真圖參考前文&#xff1a;3.3.2 Proteus第一個仿真圖 keil安裝參考前文&#xff1a;3.1.2 Keil4安裝教程 keil新建第一個項目參考前文&#xff1a;3.1…

996引擎-問題處理:實現自定義道具變身卡

996引擎-問題處理:實現自定義道具變身卡 方案一、修改角色外觀(武器、衣服、特效) 實現變身先看效果創建個NPC測試效果方案二、利用 Buff 實現變身創建:變身Buff配buff表,實現人物變形測試NPC創建道具:變身卡配item表,添加道具:變身卡觸發函數參考資料方案一、修改角色外…

AI視頻領域的DeepSeek—阿里萬相2.1圖生視頻

讓我們一同深入探索萬相 2.1 &#xff0c;本文不僅介紹其文生圖和文生視頻的使用秘籍&#xff0c;還將手把手教你如何利用它實現圖生視頻。 如下為生成的視頻效果&#xff08;我錄制的GIF動圖&#xff09; 如下為輸入的圖片 目錄 1.阿里巴巴全面開源旗下視頻生成模型萬相2.1模…

驅動 AI 邊緣計算新時代!高性能 i.MX 95 應用平臺引領未來

智慧浪潮崛起&#xff1a;AI與邊緣計算的時代 正悄然深植于我們的日常生活之中&#xff0c;無論是火熱的 ChatGPT 與 DeepSeek 語言模型&#xff0c;亦或是 Meta 智能眼鏡&#xff0c;AI 技術已經無形地影響著我們的生活。這股變革浪潮并未停歇&#xff0c;而是進一步催生了更高…

如何快速判斷IP是否為代理

1.探究IP地址的地理分布 代理IP的所在位置&#xff0c;往往與用戶實際所在地不吻合。可以通過運用WHOIS查詢工具或在線IP地址定位服務&#xff0c;輸入所需查詢的IP&#xff0c;即可獲得其地理位置信息。 若該信息顯示的位置并非用戶所在城市或顯示為知名代理服務器節點&…

從CL1看生物計算機的創新突破與發展前景:技術、應用與挑戰的多維度剖析

一、引言 1.1 研究背景與意義 隨著科技的飛速發展&#xff0c;計算機技術已經成為推動現代社會進步的核心力量之一。從最初的電子管計算機到如今的大規模集成電路計算機&#xff0c;計算機的性能得到了極大的提升&#xff0c;應用領域也不斷拓展。然而&#xff0c;傳統計算機…

AI革命先鋒:DeepSeek與藍耘通義萬相2.1的無縫融合引領行業智能化變革

云邊有個稻草人-CSDN博客 目錄 引言 一、什么是DeepSeek&#xff1f; 1.1 DeepSeek平臺概述 1.2 DeepSeek的核心功能與技術 二、藍耘通義萬相2.1概述 2.1 藍耘科技簡介 2.2 藍耘通義萬相2.1的功能與優勢 1. 全鏈條智能化解決方案 2. 強大的數據處理能力 3. 高效的模型…

zabbix圖表中文顯示方框

問題&#xff1a; zabbix安裝完成后&#xff0c;查看圖形&#xff0c;下方中文顯示為方框 思路&#xff1a; 替換字體文件&#xff0c;或者修改配置文件指向中文可以正常顯示的字體文件 方案&#xff1a; 查找資料確認影響因素 通過資料查詢得知&#xff0c;使用的字體文…