您好,登錄后才能下訂單哦!
本篇內容主要講解“java中@Async異步調用的方法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“java中@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); } }
從調用到返回函數結果才能執行下一步,稱為同步調用
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秒鐘,終端不顯示也不關閉
結束
異步調用,執行函數不用等返回結果就可以執行下一步
service層 代碼:
主要是添加了@Async注解標識這個方法
public class Service{ @Async public void test01() throws InterruptedException{ Thread.sleep(500); System.out.println("保存日志"); } }
控制層代碼模塊:
通過調用service層函數
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); } }
對于線程池的一些基本知識可看我之前的文章:
java如何正確關閉線程以及線程池(代碼實踐含源碼分析)
java線程池的創建方式詳細分析(全)
如果不指定線程池,默認使用的線程池為SimpleAsyncTaskExecutor(來一個任務就創建一個線程,不斷創建線程導致CPU過高引發OOM),自帶的線程池一般都有弊端,一般推薦使用ThreadPoolExecutor(明確線程池的資源,規避風險)
具體如下:
newFixedThreadPool:定死了線程數,任務隊列還是無界的,(最大線程數只有隊列滿了,最大線程數才會創建),所以會造成OOM
newCachedThreadPool:沒有設置最大線程數上限,創建大量的線程容易卡頓或者直接OOM
通過自定義線程池可以調整線程池的配置,更好的資源利用
@Async這個注解查找 AsyncConfigurer接口(實現類為AsyncConfigurerSupport,默認配置和方法都是空),所以可重寫接口指定線程池。
通過實現接口AsyncConfigurer
繼承AsyncConfigurerSupport
自定義TaskExecutor(替代內置任務執行器)
第三種方法:
在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; // 核心線程數 @Value("${thread.core.size}") private int coreSize; // 最大線程數 @Value("${thread.max.size}") private int maxSize; // 隊列長度 @Value("${thread.queue.size}") private int queueSize; // 通過bean注解注入 @Bean("xx") public ThreadPoolTaskExecutor taskExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); //設置線程池參數信息 taskExecutor.setCorePoolSize(coreSize); taskExecutor.setMaxPoolSize(maxSize); taskExecutor.setQueueCapacity(queueSize); taskExecutor.setThreadNamePrefix(threadPrefix); taskExecutor.setWaitForTasksToCompleteOnShutdown(true); taskExecutor.setAwaitTerminationSeconds(30); //修改拒絕策略為使用當前線程執行 taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //初始化線程池 taskExecutor.initialize(); return taskExecutor; } }
到此,相信大家對“java中@Async異步調用的方法”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。