關(guān)于java中@Async異步調(diào)用詳細(xì)解析附代碼
前言
異步調(diào)用與同步調(diào)用
- 同步調(diào)用:順序執(zhí)行,通過(guò)調(diào)用返回結(jié)果再次執(zhí)行下一個(gè)調(diào)用
- 異步調(diào)用:通過(guò)調(diào)用,無(wú)需等待返回結(jié)果,執(zhí)行下一個(gè)調(diào)用
1. @Async講解
其@Async的注解代碼如下:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {
String value() default "";
}注解可以使用在類型以及方法中
通過(guò)value定義其值,默認(rèn)是空
一般這個(gè)注解需要配合@EnableAsync,起源碼如下
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AsyncConfigurationSelector.class})
public @interface EnableAsync {
? ? Class<? extends Annotation> annotation() default Annotation.class;
? ? boolean proxyTargetClass() default false;
? ? AdviceMode mode() default AdviceMode.PROXY;
? ? int order() default Integer.MAX_VALUE;
}主要通過(guò)該注解放置在啟動(dòng)類中進(jìn)行配置啟動(dòng)
在啟動(dòng)類中添加如下:
@SpringbootApplication
@EnableAsync
public class Application{
public static void main(String[] args){
SrpingApplication.run(Application.class, args);
}
}2. 用法
2.1 同步調(diào)用
從調(diào)用到返回函數(shù)結(jié)果才能執(zhí)行下一步,稱為同步調(diào)用
service層 代碼:
public class Service{
public void test01() throws InterruptedException{
Thread.sleep(5000);
System.out.println("保存日志");
}
}控制層代碼模塊:
public class Controler{
?? ?@Autowired
?? ?private Service service;
?? ?@GetMapping("/test")
?? ?public String getTest(){
?? ??? ?try{
?? ??? ??? ?System.out.println("開(kāi)始");
?? ??? ??? ?service.test01();
?? ??? ??? ?System.out.println("結(jié)束");?? ??? ??? ?
?? ??? ?}catch(InterruptedException e){
?? ??? ??? ?e.prinStackTrace();
?? ??? ?}
?? ?}
?? ?
}通過(guò)springboot的啟動(dòng)類啟動(dòng)之后
輸出如下:
開(kāi)始
// 此為等待5秒鐘,終端不顯示也不關(guān)閉
結(jié)束
2.2 異步調(diào)用
異步調(diào)用,執(zhí)行函數(shù)不用等返回結(jié)果就可以執(zhí)行下一步
service層 代碼:
主要是添加了@Async注解標(biāo)識(shí)這個(gè)方法
public class Service{
@Async
public void test01() throws InterruptedException{
Thread.sleep(500);
System.out.println("保存日志");
}
}控制層代碼模塊:
通過(guò)調(diào)用service層函數(shù)
public class Controler{
?? ?@Autowired
?? ?private Service service;
?? ?@GetMapping("/test")
?? ?public String getTest(){
?? ??? ?try{
?? ??? ??? ?System.out.println("開(kāi)始");
?? ??? ??? ?service.test01();
?? ??? ??? ?System.out.println("結(jié)束");?? ??? ??? ?
?? ??? ?}catch(InterruptedException e){
?? ??? ??? ?e.prinStackTrace();
?? ??? ?}
?? ?}
?? ?
}以及在啟動(dòng)類中加入注解啟動(dòng) @EnableAsync
@SpringbootApplication
@EnableAsync
public class Application{
public static void main(String[] args){
SrpingApplication.run(Application.class, args);
}
}3. 自定義線程池
對(duì)于線程池的一些基本知識(shí)可看我之前的文章:
java如何正確關(guān)閉線程以及線程池(代碼實(shí)踐含源碼分析)
java線程池的創(chuàng)建方式詳細(xì)分析(全)
如果不指定線程池,默認(rèn)使用的線程池為SimpleAsyncTaskExecutor(來(lái)一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,不斷創(chuàng)建線程導(dǎo)致CPU過(guò)高引發(fā)OOM),自帶的線程池一般都有弊端,一般推薦使用ThreadPoolExecutor(明確線程池的資源,規(guī)避風(fēng)險(xiǎn))
具體如下:
- newFixedThreadPool:定死了線程數(shù),任務(wù)隊(duì)列還是無(wú)界的,(最大線程數(shù)只有隊(duì)列滿了,最大線程數(shù)才會(huì)創(chuàng)建),所以會(huì)造成OOM
- newCachedThreadPool:沒(méi)有設(shè)置最大線程數(shù)上限,創(chuàng)建大量的線程容易卡頓或者直接OOM
通過(guò)自定義線程池可以調(diào)整線程池的配置,更好的資源利用
@Async這個(gè)注解查找 AsyncConfigurer接口(實(shí)現(xiàn)類為AsyncConfigurerSupport,默認(rèn)配置和方法都是空),所以可重寫接口指定線程池。
- 通過(guò)實(shí)現(xiàn)接口AsyncConfigurer
- 繼承AsyncConfigurerSupport
- 自定義TaskExecutor(替代內(nèi)置任務(wù)執(zhí)行器)
第三種方法:
在application.xml中定義線程池的一些變量
thread.core.size=16 thread.max.size=16 thread.queue.size=30 thread.prefix=xx-
自定義線程池如下
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class ThreadPoolConfig {
?? ?// 線程名稱前綴
? ? @Value("${thread.prefix}")
? ? private String threadPrefix;
?? ?
?? ?// 核心線程數(shù)
? ? @Value("${thread.core.size}")
? ? private int coreSize;
?? ?// 最大線程數(shù)
? ? @Value("${thread.max.size}")
? ? private int maxSize;
?? ?
?? ?// 隊(duì)列長(zhǎng)度
? ? @Value("${thread.queue.size}")
? ? private int queueSize;
?? ?
?? ?// 通過(guò)bean注解注入
? ? @Bean("xx")
? ? public ThreadPoolTaskExecutor taskExecutor() {
? ? ? ? ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
? ? ? ? //設(shè)置線程池參數(shù)信息
? ? ? ? taskExecutor.setCorePoolSize(coreSize);
? ? ? ? taskExecutor.setMaxPoolSize(maxSize);
? ? ? ? taskExecutor.setQueueCapacity(queueSize);
? ? ? ? taskExecutor.setThreadNamePrefix(threadPrefix);
? ? ? ? taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
? ? ? ? taskExecutor.setAwaitTerminationSeconds(30);
? ? ? ??
? ? ? ? //修改拒絕策略為使用當(dāng)前線程執(zhí)行
? ? ? ? taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
? ? ? ??
? ? ? ? //初始化線程池
? ? ? ? taskExecutor.initialize();
? ? ? ? return taskExecutor;
? ? }
}到此這篇關(guān)于關(guān)于java中@Async異步調(diào)用詳細(xì)解析附代碼的文章就介紹到這了,更多相關(guān)java @Async異步調(diào)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用XSD校驗(yàn)Mybatis的SqlMapper配置文件的方法(2)
這篇文章主要介紹了使用XSD校驗(yàn)Mybatis的SqlMapper配置文件的方法(2)的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11
詳談Array和ArrayList的區(qū)別與聯(lián)系
下面小編就為大家?guī)?lái)一篇詳談Array和ArrayList的區(qū)別與聯(lián)系。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06
MyBatis中動(dòng)態(tài)sql的實(shí)現(xiàn)方法示例
這篇文章主要給大家介紹了關(guān)于MyBatis中動(dòng)態(tài)sql的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
常用校驗(yàn)注解之@NotNull,@NotBlank,@NotEmpty的區(qū)別及說(shuō)明
這篇文章主要介紹了常用校驗(yàn)注解之@NotNull,@NotBlank,@NotEmpty的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
Mybatis?ResultMap和分頁(yè)操作示例詳解
這篇文章主要為大家介紹了Mybatis?ResultMap和分頁(yè)操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10

