Spring Boot Async異步執(zhí)行任務(wù)過(guò)程詳解
異步調(diào)用就是不用等待結(jié)果的返回就執(zhí)行后面的邏輯,同步調(diào)用則需要等帶結(jié)果再執(zhí)行后面的邏輯。
通常我們使用異步操作都會(huì)去創(chuàng)建一個(gè)線程執(zhí)行一段邏輯,然后把這個(gè)線程丟到線程池中去執(zhí)行,代碼如下:
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(() -> {
try {
// 業(yè)務(wù)邏輯
} catch (Exception e) {
e.printStackTrace();
} finally {
}
});
這樣的方式看起來(lái)沒(méi)那么優(yōu)雅,盡管用了java的lambda。在Spring Boot中有一種更簡(jiǎn)單的方式來(lái)執(zhí)行異步操作,只需要一個(gè)@Async注解即可。
@Async
public void saveLog() {
System.err.println(Thread.currentThread().getName());
}
我們可以直接在Controller中調(diào)用這個(gè)業(yè)務(wù)方法,它就是異步執(zhí)行的,會(huì)在默認(rèn)的線程池中去執(zhí)行。需要注意的是一定要在外部的類中去調(diào)用這個(gè)方法,如果在本類調(diào)用是不起作用的,比如this.saveLog()。 最后在啟動(dòng)類上開(kāi)啟異步任務(wù)的執(zhí)行,添加@EnableAsync即可。
另外關(guān)于執(zhí)行異步任務(wù)的線程池我們也可以自定義,首先我們定義一個(gè)線程池的配置類,用來(lái)配置一些參數(shù),具體代碼如下:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 異步任務(wù)線程池配置
*
* @author yinjihuan
*/
@Configuration
@ConfigurationProperties(prefix = "spring.task.pool")
public class TaskThreadPoolConfig {
//核心線程數(shù)
private int corePoolSize = 5;
//最大線程數(shù)
private int maxPoolSize = 50;
//線程池維護(hù)線程所允許的空閑時(shí)間
private int keepAliveSeconds = 60;
//隊(duì)列長(zhǎng)度
private int queueCapacity = 10000;
//線程名稱前綴
private String threadNamePrefix = "FSH-AsyncTask-";
public String getThreadNamePrefix() {
return threadNamePrefix;
}
public void setThreadNamePrefix(String threadNamePrefix) {
this.threadNamePrefix = threadNamePrefix;
}
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getKeepAliveSeconds() {
return keepAliveSeconds;
}
public void setKeepAliveSeconds(int keepAliveSeconds) {
this.keepAliveSeconds = keepAliveSeconds;
}
public int getQueueCapacity() {
return queueCapacity;
}
public void setQueueCapacity(int queueCapacity) {
this.queueCapacity = queueCapacity;
}
}
然后我們重新定義線程池的配置:
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class AsyncTaskExecutePool implements AsyncConfigurer {
private Logger logger = LoggerFactory.getLogger(AsyncTaskExecutePool.class);
@Autowired
private TaskThreadPoolConfig config;
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(config.getCorePoolSize());
executor.setMaxPoolSize(config.getMaxPoolSize());
executor.setQueueCapacity(config.getQueueCapacity());
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
executor.setThreadNamePrefix(config.getThreadNamePrefix());
//線程池對(duì)拒絕任務(wù)(無(wú)線程可用)的處理策略,目前只支持AbortPolicy、CallerRunsPolicy
//AbortPolicy:直接拋出java.util.concurrent.RejectedExecutionException異常 -->
//CallerRunsPolicy:主線程直接執(zhí)行該任務(wù),執(zhí)行完之后嘗試添加下一個(gè)任務(wù)到線程池中,可以有效降低向線程池內(nèi)添加任務(wù)的速度 -->
//DiscardOldestPolicy:拋棄舊的任務(wù)、暫不支持;會(huì)導(dǎo)致被丟棄的任務(wù)無(wú)法再次被執(zhí)行 -->
//DiscardPolicy:拋棄當(dāng)前任務(wù)、暫不支持;會(huì)導(dǎo)致被丟棄的任務(wù)無(wú)法再次被執(zhí)行 -->
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {// 異步任務(wù)中異常處理
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable arg0, Method arg1, Object... arg2) {
logger.error("=========================="+arg0.getMessage()+"=======================", arg0);
logger.error("exception method:" + arg1.getName());
}
};
}
}
配置完之后我們的異步任務(wù)執(zhí)行的線程池就是我們自定義的了,我們可以通過(guò)在屬性文件里面配置線程池的大小等等信息,也可以使用默認(rèn)的配置:
spring.task.pool.maxPoolSize=100
最后講下線程池配置的拒絕策略,當(dāng)我們的線程數(shù)量高于線程池的處理速度時(shí),任務(wù)會(huì)被緩存到本地的隊(duì)列中,隊(duì)列也是有大小的,如果超過(guò)了這個(gè)大小,我們需要有拒絕的策略,不然就會(huì)內(nèi)存溢出了,目前支持2種拒絕策略:
- AbortPolicy: 直接拋出java.util.concurrent.RejectedExecutionException異常
- CallerRunsPolicy: 主線程直接執(zhí)行該任務(wù),執(zhí)行完之后嘗試添加下一個(gè)任務(wù)到線程池中,可以有效降低向線程池內(nèi)添加任務(wù)的速度
- 建議大家用CallerRunsPolicy策略,因?yàn)楫?dāng)隊(duì)列中的任務(wù)滿了之后,如果直接拋異常,那么這個(gè)任務(wù)就會(huì)被丟棄,如果是CallerRunsPolicy策略會(huì)用主線程去執(zhí)行,就是同步執(zhí)行,最起碼這樣任務(wù)不會(huì)丟棄。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Spring Boot @Async 異步任務(wù)執(zhí)行方法
- Spring Boot利用@Async異步調(diào)用:使用Future及定義超時(shí)詳解
- Spring Boot利用@Async異步調(diào)用:ThreadPoolTaskScheduler線程池的優(yōu)雅關(guān)閉詳解
- spring boot異步(Async)任務(wù)調(diào)度實(shí)現(xiàn)方法
- Spring Boot 使用WebAsyncTask異步返回結(jié)果
- spring boot使用自定義配置的線程池執(zhí)行Async異步任務(wù)
- 深入理解spring boot異步調(diào)用方式@Async
- spring boot 使用@Async實(shí)現(xiàn)異步調(diào)用方法
相關(guān)文章
SWT(JFace)體驗(yàn)之打開(kāi)多個(gè)Form
SWT(JFace)體驗(yàn)之打開(kāi)多個(gè)Form的實(shí)現(xiàn)代碼。2009-06-06
java開(kāi)發(fā)SSM框架具有rest風(fēng)格的SpringMVC
這篇文章主要介紹了java開(kāi)發(fā)中如何使SSM框架具有rest風(fēng)格的SpringMVC實(shí)現(xiàn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-10-10
java.lang.IllegalStateException異常解決
異常是程序在執(zhí)行過(guò)程中遇到的錯(cuò)誤或異常情況,本文就來(lái)介紹一下java.lang.IllegalStateException異常解決,感興趣的可以了解一下2023-11-11
Spring中的SpringData詳細(xì)說(shuō)明
這篇文章主要介紹了Spring中的SpringData詳細(xì)說(shuō)明,Spring Data 是Spring 的一個(gè)子項(xiàng)目, 旨在統(tǒng)一和簡(jiǎn)化對(duì)各類型持久化存儲(chǔ), 而不拘泥于是關(guān)系型數(shù)據(jù)庫(kù)還是NoSQL 數(shù)據(jù)存儲(chǔ),需要的朋友可以參考下2023-11-11
FeignClient實(shí)現(xiàn)接口調(diào)用方式(不同參數(shù)形式)
這篇文章主要介紹了FeignClient實(shí)現(xiàn)接口調(diào)用方式(不同參數(shù)形式),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03

