非同步呼叫與同步呼叫
同步呼叫:順序執行,透過呼叫傳回結果再次執行下一個調用
異步調用:透過調用,無需等待返回結果,執行下一個調用
其@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
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非同步呼叫的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!