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