springboot之異步任務
啟動類:添加@EnableAsync注解
@SpringBootApplication @EnableAsync public class Application{ public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
異步任務執行類 添加@Async注解
import java.util.concurrent.Future; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Component; /** * 功能描述:異步任務業務類(@Async也可添加在方法上,@Async放在類上,表示類內方法皆為異步方法) */ @Component @Async("taskExecutor")//使用自己的線程池記得括號內填寫線程池bean的名字,詳見下邊線程池配置;如果使用默認線程池,則直接使用@Async public class AsyncTask { //獲取異步結果 public Future<String> task4() throws InterruptedException{ long begin = System.currentTimeMillis(); Thread.sleep(2000L); long end = System.currentTimeMillis(); System.out.println("任務4耗時="+(end-begin)); return new AsyncResult<String>("任務4"); } public Future<String> task5() throws InterruptedException{ long begin = System.currentTimeMillis(); Thread.sleep(3000L); long end = System.currentTimeMillis(); System.out.println("任務5耗時="+(end-begin)); return new AsyncResult<String>("任務5"); } public Future<String> task6() throws InterruptedException{ long begin = System.currentTimeMillis(); Thread.sleep(1000L); long end = System.currentTimeMillis(); System.out.println("任務6耗時="+(end-begin)); return new AsyncResult<String>("任務6"); } }
異步線程池
package com.boot.common.conf; import java.util.concurrent.ThreadPoolExecutor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; /** * 線程池配置(線程池可以不配置,使用默認線程池,注意:在異步方法或類添加@Async注解是:@Async;如果自己配置了線程池,異步方法或類使用自己配置的線程池,則注解應為:@Async("taskExecutor")括號內為自己配置的線程池對象bean的名字) * @author zhh * */ @Configuration @EnableAsync public class ThreadPoolTaskConfig { private static final int corePoolSize = 10; // 核心線程數(默認線程數)線程池創建時候初始化的線程數 private static final int maxPoolSize = 100; // 最大線程數 線程池最大的線程數,只有在緩沖隊列滿了之后才會申請超過核心線程數的線程 private static final int keepAliveTime = 10; // 允許線程空閑時間(單位:默認為秒)當超過了核心線程之外的線程在空閑時間到達之后會被銷毀 private static final int queueCapacity = 200; // 緩沖隊列數 用來緩沖執行任務的隊列 private static final String threadNamePrefix = "Async-Service-"; // 線程池名前綴 方便我們定位處理任務所在的線程池 @Bean("taskExecutor") // bean的名稱,默認為首字母小寫的方法名 public ThreadPoolTaskExecutor taskExecutor(){ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(corePoolSize); executor.setMaxPoolSize(maxPoolSize); executor.setQueueCapacity(queueCapacity); executor.setKeepAliveSeconds(keepAliveTime); executor.setThreadNamePrefix(threadNamePrefix); // 線程池對拒絕任務的處理策略 采用了CallerRunsPolicy策略,當線程池沒有處理能力的時候,該策略會直接在 execute 方法的調用線程中運行被拒絕的任務;如果執行程序已關閉,則會丟棄該任務 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 初始化 executor.initialize(); return executor; } }
異步任務調用
import java.util.concurrent.Future; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.jincou.task.AsyncTask; import com.jincou.util.JsonData; @RestController @RequestMapping("/api/v1") public class UserController { @Autowired private AsyncTask task; @GetMapping("async_task") public JsonData exeTask() throws InterruptedException{ long begin = System.currentTimeMillis(); Future<String> task4 = task.task4(); Future<String> task5 = task.task5(); Future<String> task6 = task.task6(); /** *如果需要監控異步任務是否完成,可以使用以下方式 **/ //如果都執行完成就可以跳出循環,isDone方法如果此任務完成,true for(;;){ if (task4.isDone() && task5.isDone() && task6.isDone()) { break; } } long end = System.currentTimeMillis(); long total = end-begin; System.out.println("執行總耗時="+total); return JsonData.buildSuccess(total); } }
注意事項:
優點:使用異步任務比同步任務耗時少,提高后台處理性能。
如下方式會使@Async失效
一、異步方法使用static修飾
二、異步類沒有使用@Component注解(或其他注解)導致spring無法掃描到異步類
三、異步方法不能與調用異步方法的方法在同一個類中
四、類中需要使用@Autowired或@Resource等注解自動注入,不能自己手動new對象
五、如果使用SpringBoot框架必須在啟動類中增加@EnableAsync注解
六、在Async 方法上標注@Transactional是沒用的。 在Async 方法調用的方法上標注@Transactional 有效。
原文摘自:https://blog.csdn.net/k0307x1990y/article/details/91950584