SpringBoot實現異步調用的方法

在Java中使用Spring Boot實現異步請求和異步調用是一個常見的需求,可以提高應用程序的性能和響應能力。以下是實現這兩種異步操作的基本方法:

一、異步請求(Asynchronous Request)

異步請求允許客戶端發送請求后立即返回,而不需要等待服務器處理完成,異步調用允許在服務端異步執行方法,不阻塞主線程。

二、在 Spring Boot 中,實現異步調用主要有以下幾種方法:
1. 使用 @Async 注解
步驟:
  1. 啟用異步支持:在主類上添加 @EnableAsync
  2. 定義異步方法:在需要異步執行的方法上使用 @Async 注解。
  3. 自定義線程池(可選):提高異步任務的線程管理效率,以便異步方法能夠在獨立的線程中執行
示例代碼:

主類:

package com.work;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication(scanBasePackages = {"com.work.*"})
@EnableAsync
//@EnableScheduling
public class SpringBootWorkApplication {public static void main(String[] args) {SpringApplication.run(SpringBootWorkApplication.class, args);}
}

異步方法:

package com.work.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
/*** 異步調用service* @author summer*/
@Service
@Slf4j
public class AsyncService {/*** 使用 @Async 注解 實現異步調用* taskExecutor為自定義線程池,指定自定義線程池* @return* @throws InterruptedException*/@Async("taskExecutor")public void async(){log.info("async異步任務開始: " + Thread.currentThread().getName());try {// 模擬耗時操作(實際工作中,此處寫業務邏輯處理)  Thread.sleep(30000); } catch (InterruptedException e) {e.printStackTrace();}log.info("async異步任務完成");}
}
自定義線程池(可選):
package com.work.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/*** 自定義異步線程執行線程池* @author summer**/
@Configuration
public class ExecutorConfig {@Bean(name = "taskExecutor")public TaskExecutor  taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(50);executor.setThreadNamePrefix("TaskExecutor-");executor.initialize();return executor;}
}

@Async("taskExecutor") 中指定自定義線程池。

調用:
package com.work.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.work.common.result.CommonResult;
import com.work.service.AsyncService;
import lombok.extern.slf4j.Slf4j;/*** 測試異步執行Controller* @author summer**/
@RestController
@RequestMapping("/async")
@Slf4j
public class AsyncTestController {@Autowiredprivate AsyncService asyncService;@GetMapping("/async")public CommonResult<String> async() {asyncService.async();log.info("async異步任務調用成功");return CommonResult.success("async異步任務調用成功");}
}

異步方法休眠30秒,可以看到控制臺打印的日志

線程池配置建議
  • CPU 密集型任務:建議核心線程數為 CPU 核心數的 n 倍,最大線程數為核心線程數的 2 倍。
  • IO 密集型任務:建議核心線程數設置為較大的值,最大線程數可以為核心線程數的 2 倍甚至更多。

合理配置線程池可以避免線程饑餓和死鎖等問題,提升系統的吞吐量。

2. 使用 Java 原生線程池

Spring 提供線程池,但可以直接使用 Java 原生的線程池來實現異步。

示例代碼:
package com.work.service;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;/*** 異步調用service* @author summer**/
@Service
@Slf4j
public class AsyncService{/*** 使用 Java 原生線程池來實現異步調用*/public void asyncThreadPool() {ThreadPoolExecutor pool=new ThreadPoolExecutor(5, 10, 2, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(100),new ThreadPoolExecutor.CallerRunsPolicy());pool.execute(() -> {log.info("asyncThreadPool異步任務開始: " + Thread.currentThread().getName());try {// 模擬耗時操作(實際工作中,此處寫業務邏輯處理)  Thread.sleep(30000);} catch (InterruptedException e) {e.printStackTrace();}log.info("asyncThreadPool異步任務完成");});}
}
調用:
package com.work.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.work.common.result.CommonResult;
import com.work.service.AsyncService;
import lombok.extern.slf4j.Slf4j;/*** 測試異步執行Controller* @author summer**/
@RestController
@RequestMapping("/async")
@Slf4j
public class AsyncTestController {@Autowiredprivate AsyncService asyncService;@GetMapping("/asyncThreadPool")public CommonResult<String> asyncThreadPool() {asyncService.asyncThreadPool();log.info("asyncThreadPool異步任務調用成功");return CommonResult.success("asyncThreadPool異步任務調用成功");}
}

異步方法休眠30秒,可以看到控制臺打印的日志

3. 使用 Spring 的 TaskExecutor

TaskExecutor 是 Spring 提供的抽象接口,適合用來執行異步任務。

配置 TaskExecutor:
package com.work.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/*** 自定義異步線程執行線程池* @author summer**/
@Configuration
public class ExecutorConfig {@Bean(name = "taskExecutor")public TaskExecutor  taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(50);executor.setThreadNamePrefix("TaskExecutor-");executor.initialize();return executor;}
}
示例代碼:
package com.work.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
/*** 異步調用service* @author summer**/
@Service
@Slf4j
public class AsyncService{@Autowiredprivate TaskExecutor taskExecutor;/*** 使用 Spring 的 TaskExecutor 來實現異步調用*/public void asyncExecutor() {taskExecutor.execute(() -> {log.info("asyncExecutor異步任務開始:" + Thread.currentThread().getName());try {// 模擬耗時操作(實際工作中,此處寫業務邏輯處理)  Thread.sleep(30000);} catch (InterruptedException e) {e.printStackTrace();}log.info("asyncExecutor異步任務完成");});}
}
調用:
package com.work.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.work.common.result.CommonResult;
import com.work.service.AsyncService;
import lombok.extern.slf4j.Slf4j;/*** 測試異步執行Controller* @author summer**/
@RestController
@RequestMapping("/async")
@Slf4j
public class AsyncTestController {@Autowiredprivate AsyncService asyncService;@GetMapping("/asyncExecutor")public CommonResult<String> asyncExecutor() {asyncService.asyncExecutor();log.info("asyncExecutor異步任務調用成功");return CommonResult.success("asyncExecutor異步任務調用成功");}
}

異步方法休眠30秒,可以看到控制臺打印的日志

三、什么時候使用異步請求

異步請求在以下情況下特別有用:

  • 長時間運行的任務:例如文件上傳、復雜計算、大量數據處理等。
  • I/O操作:例如數據庫查詢、調用外部API、文件讀寫等。
  • 資源密集型任務:例如圖像處理、視頻編碼等。
四、總結

方法

優點

缺點

@Async 注解

簡單易用,與 Spring 集成良好

需要 Spring 容器管理的 Bean 才能生效

ExecutorService

更底層、更靈活

手動管理線程池

TaskExecutor

Spring 提供的抽象,方便擴展

配置稍顯復雜

這些示例展示了如何在Spring Boot中實現異步請求和異步調用。Spring Boot提供了`@Async`注解和`Java原生線程池`、`TaskExecutor`來實現這一功能,提高了應用程序的并發處理能力,開發者可以根據不同的需求選擇合適的異步處理方式。

合理配置線程池,以確保最佳性能和資源利用,正確處理異步任務中的異常,以及在合適的場景中應用異步處理技術,是開發高性能應用的關鍵。

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

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

相關文章

xwiki自定義認證實現單點登錄

xwiki支持自定義認證 繼承XWikiAuthServiceImpl類后將類配置到WEB-INFO下xwiki.cfg的xwiki.authentication.authclass屬性上開啟自定義認證。 官方文檔&#xff1a;https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Authentication/ 官方自定義認證的示例&#…

使用vite新建vue3項目 以及elementui的使用 vite組件問題

項目創建 在創建項目之前我們應該在終端中輸入 node -v 和 npm -v 只有它們都能正常查看版本號才說明我們之前是已經安裝完成的。 接下來我們在合適的目錄下輸入npm create vitelatest 它會要求你輸入項目的名稱&#xff0c;這個名稱和我們之前通過cil創建的命名規則一樣。…

音頻錄制小妙招-自制工具-借助瀏覽器錄一段單聲道16000采樣率wav格式音頻

先看效果 1、打開頁面 2、點擊開始錄音&#xff0c;彈出權限提示&#xff0c;點擊“僅這次訪問時允許” 3、錄完后&#xff0c;點擊停止 4、文件自動下載到默認目錄 上代碼 js 部分 document.addEventListener(DOMContentLoaded, () > {const startBtn document.getEleme…

Mysql-經典實戰案例(10):如何用PT-Archiver完成大表的自動歸檔

真實痛點&#xff1a;電商訂單表存儲優化場景 現狀分析 某電商平臺訂單表&#xff08;order_info&#xff09;每月新增500萬條記錄 主庫&#xff1a;高頻讀寫&#xff0c;SSD存儲&#xff08;空間告急&#xff09;歷史庫&#xff1a;HDD存儲&#xff0c;只讀查詢 優化目標 …

CUDA編程面試高頻30題

1. 什么是CUDA&#xff1f;它與GPU的關系是什么&#xff1f; 答: CUDA&#xff08;Compute Unified Device Architecture&#xff09;是由NVIDIA開發的一種并行計算平臺和應用程序接口模型。它允許開發者利用NVIDIA GPU進行通用計算任務&#xff0c;而不僅僅是圖形渲染。CUDA提…

數學建模 繪圖 圖表 可視化(3)

文章目錄 前言二維散點圖系列坐標圖數據分布特征&#xff0c;Q-Q、P-P圖分類圖一般的曲線圖峰巒圖總結參考資料 前言 承接上期 數學建模 繪圖 圖表 可視化&#xff08;1&#xff09;的總體描述&#xff0c;這期我們繼續跟隨《Python 數據可視化之美 專業圖表繪制指南》步伐來學…

【數據結構】棧(Stack)、隊列(Queue)、雙端隊列(Deque) —— 有碼有圖有真相

目錄 棧和隊列 1. 棧&#xff08;Stack&#xff09; 1.1 概念 1.2 棧的使用&#xff08;原始方法&#xff09; 1.3 棧的模擬實現 【小結】 2. 棧的應用場景 1、改變元素的序列 2、將遞歸轉化為循環 3、逆波蘭表達式求值 4、括號匹配 5、出棧入棧次序匹配 6、最小棧…

【強化學習】Reward Model(獎勵模型)詳細介紹

&#x1f4e2;本篇文章是博主強化學習&#xff08;RL&#xff09;領域學習時&#xff0c;用于個人學習、研究或者欣賞使用&#xff0c;并基于博主對相關等領域的一些理解而記錄的學習摘錄和筆記&#xff0c;若有不當和侵權之處&#xff0c;指出后將會立即改正&#xff0c;還望諒…

國家雪亮工程政策護航,互聯網監控管理平臺鑄就安全防線

在當今社會&#xff0c;公共安全是國家發展的重要基石&#xff0c;也是人民安居樂業的基本保障。為了打造更高水平的平安中國&#xff0c;國家推出了意義深遠的雪亮工程&#xff0c;并出臺了一系列相關政策&#xff0c;為公共安全事業保駕護航。而互聯網監控管理平臺作為雪亮工…

藍橋杯 第十天 2019國賽第4題 矩陣計數

最后一個用例超時了&#xff0c;還是記錄一下 import java.util.Scanner;public class Main {static int visited[][];static int count 0;static int n,m;public static void main(String[]args) {Scanner scan new Scanner(System.in);n scan.nextInt();//2m scan.nextIn…

coding ability 展開第五幕(二分查找算法)超詳細!!!!

. . 文章目錄 前言二分查找搜索插入的位置思路 x的平方根思路 山脈數組的峰頂索引思路 尋找旋轉排序數組中的最小值思路 總結 前言 本專欄上篇博客已經把滑動指針收尾啦 現在還是想到核心——一段連續的區間&#xff0c;有時候加上哈希表用起來很爽 今天我們來學習新的算法知識…

BEVFormer報錯(預測場景與真值場景的sample_token不匹配)

在運行test.py時報錯&#xff1a; BEVFormer/projects/mmdet3d_plugin/datasets/nuscnes_eval.py&#xff1a; init()函數報錯 assert set(self.pred_boxes.sample_tokens) set(self.gt_boxes.sample_tokens), \"Samples in split doesnt match samples in predictions…

網絡安全威脅與防護措施(下)

8. 惡意軟件&#xff08;Malware&#xff09; **惡意軟件&#xff08;Malware&#xff0c;Malicious Software&#xff09;**是指旨在通過破壞、破壞或未經授權訪問計算機系統、網絡或設備的程序或代碼。惡意軟件通常用于竊取敏感信息、破壞系統、竊取資源、干擾正常操作&…

基于springboot的母嬰商城系統(018)

摘 要 現代經濟快節奏發展以及不斷完善升級的信息化技術&#xff0c;讓傳統數據信息的管理升級為軟件存儲&#xff0c;歸納&#xff0c;集中處理數據信息的管理方式。本母嬰商城系統就是在這樣的大環境下誕生&#xff0c;其可以幫助管理者在短時間內處理完畢龐大的數據信息&am…

shell 腳本搭建apache

#!/bin/bash # Set Apache version to install ## author: yuan# 檢查外網連接 echo "檢查外網連接..." ping www.baidu.com -c 3 > /dev/null 2>&1 if [ $? -eq 0 ]; thenecho "外網通訊良好&#xff01;" elseecho "網絡連接失敗&#x…

使用OBS進行webRTC推流參考

參考騰訊云官方文檔&#xff1a; 云直播 OBS WebRTC 推流_騰訊云 說明非常詳細&#xff0c;分為通過WHIP和OBS插件的形式進行推流。 注意&#xff1a;通過OBS插件的形式進行推流需要使用較低的版本&#xff0c;文檔里有說明&#xff0c;需要仔細閱讀。

Excel 小黑第18套

對應大貓18 .txt 文本文件&#xff0c;點數據 -現有鏈接 -瀏覽更多 &#xff08;文件類型&#xff1a;可以點開文件看是什么分隔的&#xff09; 雙擊修改工作表名稱 為表格添加序號&#xff1a;在數字那修改格式為文本&#xff0c;輸入第一個序號樣式&#xff08;如001&#…

快速入手-基于Django的mysql配置(三)

Django開發操作數據庫更簡單&#xff0c;內部提供了ORM框架。比如mysql&#xff0c;舊版本用pymysql對比較多&#xff0c;新的版本采用mysqlclient。 1、安裝mysql模塊 pip install mysqlclient 2、Django的ORM主要做了兩件事 &#xff08;1&#xff09;CRUD數據庫中的表&am…

【總結篇】java多線程,新建線程有幾種寫法,以及每種寫法的優劣勢

java多線程 新建線程有幾種寫法,以及每種寫法的優劣勢 [1/5]java多線程 新建線程有幾種寫法–繼承Thread類以及他的優劣勢[2/5]java多線程-新建線程有幾種寫法–實現Runnable接口以及他的優劣勢[3/5]java多線程 新建線程有幾種寫法–實現Callable接口結合FutureTask使用以及他的…

基于YOLOv8與ByteTrack的車輛行人多目標檢測與追蹤系統

作者主頁&#xff1a;編程千紙鶴 作者簡介&#xff1a;Java領域優質創作者、CSDN博客專家 、CSDN內容合伙人、掘金特邀作者、阿里云博客專家、51CTO特邀作者、多年架構師設計經驗、多年校企合作經驗&#xff0c;被多個學校常年聘為校外企業導師&#xff0c;指導學生畢業設計并參…