如何在Java Spring實(shí)現(xiàn)異步執(zhí)行(詳細(xì)篇)
前言
在 Java 開(kāi)發(fā)中,異步執(zhí)行是提高系統(tǒng)性能和響應(yīng)速度的重要手段之一。在 Spring 框架中,提供了非常方便的方式來(lái)實(shí)現(xiàn)異步執(zhí)行。通過(guò)將任務(wù)異步化,能夠讓系統(tǒng)在等待某些耗時(shí)操作(如網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)庫(kù)查詢、文件處理等)完成時(shí),不阻塞主線程,從而提高應(yīng)用的吞吐量和響應(yīng)速度。
本文將介紹如何在 Spring 中實(shí)現(xiàn)異步執(zhí)行,使用的技術(shù)包括 @Async 注解、Executor、Future 等。
1. 使用 @Async 實(shí)現(xiàn)異步執(zhí)行
1.1 啟用異步執(zhí)行支持
在 Spring Boot 中,我們可以通過(guò) @EnableAsync 注解啟用異步支持。
在主應(yīng)用類(lèi)或配置類(lèi)中,添加 @EnableAsync 注解:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync // 啟用異步支持
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}1.2 創(chuàng)建異步方法
一旦啟用異步支持,我們可以通過(guò) @Async 注解將方法標(biāo)記為異步執(zhí)行。默認(rèn)情況下,方法會(huì)在另一個(gè)線程中執(zhí)行,并且不會(huì)阻塞調(diào)用者的線程。
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
// 這個(gè)方法會(huì)異步執(zhí)行
@Async
public void asyncMethod() {
try {
// 模擬一個(gè)耗時(shí)的任務(wù)
System.out.println("異步方法開(kāi)始執(zhí)行");
Thread.sleep(2000);
System.out.println("異步方法執(zhí)行完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}1.3 調(diào)用異步方法
我們可以通過(guò)調(diào)用 @Async 注解的方法來(lái)觸發(fā)異步執(zhí)行。調(diào)用異步方法時(shí),方法的執(zhí)行將會(huì)在一個(gè)新的線程中進(jìn)行,而不會(huì)阻塞主線程。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/startAsync")
public String startAsyncProcess() {
asyncService.asyncMethod();
return "異步任務(wù)已啟動(dòng)!";
}
}1.4 異步執(zhí)行的線程池配置
默認(rèn)情況下,Spring 會(huì)使用簡(jiǎn)單的 SimpleAsyncTaskExecutor 來(lái)執(zhí)行異步方法。但你可以根據(jù)需要自定義線程池,以優(yōu)化性能。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class AsyncConfig {
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 核心線程池大小
executor.setMaxPoolSize(10); // 最大線程池大小
executor.setQueueCapacity(25); // 等待隊(duì)列大小
executor.setThreadNamePrefix("async-task-"); // 線程名前綴
executor.initialize();
return executor;
}
}然后,將 @Async 注解的默認(rèn)執(zhí)行器切換到自定義的線程池:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
@Async
public void asyncMethod() {
taskExecutor.execute(() -> {
try {
System.out.println("異步任務(wù)開(kāi)始執(zhí)行");
Thread.sleep(2000);
System.out.println("異步任務(wù)執(zhí)行完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}2. 使用 Future 獲取異步執(zhí)行的結(jié)果
有時(shí)我們希望在異步方法執(zhí)行完成后獲取結(jié)果。這時(shí)可以使用 Future 或 CompletableFuture 來(lái)異步獲取方法的執(zhí)行結(jié)果。
2.1 使用 Future 獲取結(jié)果
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Async
public Future<String> asyncMethodWithResult() {
try {
Thread.sleep(2000); // 模擬耗時(shí)任務(wù)
return new CompletableFuture<String>().completedFuture("任務(wù)完成");
} catch (InterruptedException e) {
e.printStackTrace();
return new CompletableFuture<String>().completedFuture("任務(wù)失敗");
}
}
}2.2 調(diào)用異步方法并獲取結(jié)果
在調(diào)用異步方法時(shí),可以通過(guò) Future 獲取返回結(jié)果:
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.Future;
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/startAsync")
public String startAsyncProcess() throws Exception {
Future<String> result = asyncService.asyncMethodWithResult();
// 獲取異步執(zhí)行的結(jié)果
return "異步任務(wù)結(jié)果: " + result.get(); // 阻塞直到任務(wù)完成
}
}2.3 使用 CompletableFuture
CompletableFuture 提供了更豐富的 API,可以組合多個(gè)異步任務(wù),處理異常等。它在 Spring 4.0 引入,可以用于處理更復(fù)雜的異步邏輯。
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Async
public CompletableFuture<String> asyncMethodWithResult() {
try {
Thread.sleep(2000); // 模擬耗時(shí)任務(wù)
return CompletableFuture.completedFuture("任務(wù)完成");
} catch (InterruptedException e) {
e.printStackTrace();
return CompletableFuture.completedFuture("任務(wù)失敗");
}
}
}2.4 調(diào)用異步方法并獲取結(jié)果
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;
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/startAsync")
public String startAsyncProcess() throws Exception {
CompletableFuture<String> result = asyncService.asyncMethodWithResult();
// 獲取異步執(zhí)行的結(jié)果
return "異步任務(wù)結(jié)果: " + result.get(); // 阻塞直到任務(wù)完成
}
}3. 異常處理
在異步執(zhí)行中,捕獲并處理異常是非常重要的。Spring 的異步方法本身不會(huì)直接拋出異常,因此需要通過(guò) Future 或 CompletableFuture 來(lái)捕獲和處理異步任務(wù)中的異常。
3.1 異常處理示例
import java.util.concurrent.CompletableFuture;
public class AsyncService {
@Async
public CompletableFuture<String> asyncMethodWithError() {
try {
// 模擬出現(xiàn)錯(cuò)誤
if (true) {
throw new RuntimeException("異步任務(wù)出錯(cuò)");
}
return CompletableFuture.completedFuture("任務(wù)完成");
} catch (Exception e) {
return CompletableFuture.completedFuture("任務(wù)失?。? + e.getMessage());
}
}
}4. 總結(jié)
- @Async 是 Spring 提供的一種方便的方式來(lái)實(shí)現(xiàn)異步執(zhí)行。它允許我們將方法標(biāo)記為異步,Spring 會(huì)自動(dòng)在另一個(gè)線程中執(zhí)行該方法。
- 異步執(zhí)行線程池:通過(guò)配置線程池,控制并發(fā)任務(wù)的執(zhí)行數(shù)量和資源管理,避免過(guò)多的線程造成資源浪費(fèi)。
- Future 和 CompletableFuture:提供了一種方式來(lái)獲取異步任務(wù)的執(zhí)行結(jié)果,支持阻塞等待結(jié)果或進(jìn)行更復(fù)雜的異步任務(wù)組合和處理。
- 異常處理:異步方法中的異常需要顯式地進(jìn)行捕獲和處理,因?yàn)?Spring 的異步方法不會(huì)自動(dòng)拋出異常。
Spring Boot 中的異步執(zhí)行可以幫助提高系統(tǒng)的吞吐量和響應(yīng)速度,特別是對(duì)于需要進(jìn)行長(zhǎng)時(shí)間任務(wù)的操作,能夠避免阻塞主線程,提高用戶體驗(yàn)。
到此這篇關(guān)于Java Spring 異步執(zhí)行 | 詳細(xì)篇的文章就介紹到這了,更多相關(guān)Java Spring 異步執(zhí)行 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于jpa中無(wú)法刪除onetomany中many問(wèn)題的解決
這篇文章主要介紹了關(guān)于jpa中無(wú)法刪除onetomany中many問(wèn)題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Spring Boot多模塊化后,服務(wù)間調(diào)用的坑及解決
這篇文章主要介紹了Spring Boot多模塊化后,服務(wù)間調(diào)用的坑及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
IntelliJ IDEA里找不到j(luò)avax.servlet的jar包的解決方法
這篇文章主要介紹了IntelliJ IDEA里找不到j(luò)avax.servlet的jar包的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
如何使用JDBC連接數(shù)據(jù)庫(kù)并執(zhí)行SQL語(yǔ)句
JDBC是Java數(shù)據(jù)庫(kù)連接的縮寫(xiě),是Java程序與數(shù)據(jù)庫(kù)進(jìn)行交互的標(biāo)準(zhǔn)API。JDBC主要包括Java.sql和javax.sql兩個(gè)包,通過(guò)DriverManager獲取數(shù)據(jù)庫(kù)連接對(duì)象Connection,并通過(guò)Statement或PreparedStatement執(zhí)行SQL語(yǔ)句2023-04-04
springboot layui hutool Excel導(dǎo)入的實(shí)現(xiàn)
本文主要介紹了springboot layui hutool Excel導(dǎo)入的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-03-03
Java實(shí)現(xiàn)Word轉(zhuǎn)PDF的兩種常見(jiàn)方案和性能實(shí)測(cè)
這篇文章對(duì)比了Java后端開(kāi)發(fā)中Word轉(zhuǎn)PDF的兩種常見(jiàn)方案,即docx4j(純Java實(shí)現(xiàn))和LibreOffice(調(diào)用Office原生引擎),下面小編就和大家詳細(xì)介紹一下具體實(shí)現(xiàn)方法吧2026-01-01
Spring Data MongoDB的核心用法 附示例代碼
本文將系統(tǒng)梳理Spring Data MongoDB 的核心用法,涵蓋實(shí)體類(lèi)注解、增刪改查、條件查詢、分頁(yè)排序等常見(jiàn)場(chǎng)景,并提供可直接復(fù)用的代碼示例,感興趣的朋友跟隨小編一起看看吧2026-02-02
SpringBoot全局異常處理之多個(gè)處理器匹配順序(最新推薦)
這篇文章主要介紹了SpringBoot全局異常處理之多個(gè)處理器匹配順序(最新推薦),調(diào)試源碼可見(jiàn)匹配順序?yàn)椋寒惓蛹?jí)高者優(yōu)先,再清楚點(diǎn),子類(lèi)異常處理器優(yōu)先,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2024-03-03
詳解Springboot之Logback的使用學(xué)習(xí)
Logback是SpringBoot內(nèi)置的日志處理框架,你會(huì)發(fā)現(xiàn)spring-boot-starter其中包含了spring-boot-starter-logging,該依賴內(nèi)容就是Spring Boot默認(rèn)的日志框架logback,本文詳細(xì)介紹了該框架 ,需要的朋友可以參考下2021-05-05

