使用Spring的@Async創建異步方法


使用Spring的@Async創建異步方法

在開發系統的過程中,通常會考慮到系統的性能問題,提升系統性能的一個重要思想就是“串行”改“並行”。說起“並行”自然離不開“異步”,今天我們就來聊聊如何使用Spring的@Async的異步注解。

假設場景

你有一個很耗時的服務,我們在下面的例子中用線程休眠來模擬,服務執行需要5秒鍾。假設一個請求需要調用這個服務3次,如果按照“串行”的方法,將至少需要15秒鍾。那么為了提升系統的性能,我們采用“並行”的方法,我們最樂觀的情況下,只需要5秒就可以了。有人可能會說這個很簡單,我們寫個多線程的方法就可以了。但是,今天我們看看Spring為我們提供的方法,它使得開發的過程更簡單。

創建異步方法

首先,使用IDEA工具創建Spring-Boot項目,並且選擇依賴包Lombok,具體步驟略。然后創建BusyService類,並創建busyMethod方法,具體如下:

@Service
@Slf4j
public class BusyService {
 @Async
 public CompletableFuture<String> busyMethod(String name) throws InterruptedException {
 log.info(name);
 String s = "Hello,"+name+"!";
 //模擬耗時操作,5秒
 Thread.sleep(5000);
 return CompletableFuture.completedFuture(s);
 }
}

  

其中,BusyService上的注解@Service標識着它會被Spring初始化為一個實例,而@Slf4j則標識着我們可以直接使用log打印日志。然后我們再看看busyMethod方法,它的返回值是CompletableFuture,CompletableFuture繼承自Future,它可以把多個異步執行的結果合並到一個單獨的異步結果中,CompletableFuture是任何異步服務所需要的。我們再看看busyMethod方法上的注解@Async,這個注解是我們今天的主角,它標識着這個方法是異步方法,調用它時是異步調用的。再看看方法體中的內容,我們使用了線程休眠模擬那些耗時的服務,並返回CompletableFuture。

Executor線程池

我們在系統定義一個Executor的Bean,使得異步調用時,使用Executor線程池的線程去執行。這里為了方便,我們直接在Spring-Boot的啟動類中增加這個Bean。

@Bean
public Executor taskExecutor() {
 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
 executor.setCorePoolSize(3);
 executor.setMaxPoolSize(3);
 executor.setQueueCapacity(500);
 executor.setThreadNamePrefix("Java同學會-");
 executor.initialize();
 return executor;
}

  

我們定義了最大的並發線程數為3,並且定義了隊列中的最大任務數為500,線程名字的前綴為“Java同學會”,在log打印日志時,凡是線程池中的線程執行的,都會打印出“Java同學會”的線程名字。當然你還可以增加一些其他的設置。如果你不配置Executor這個Bean,Spring會自動創建SimpleAsyncTaskExecutor,並使用它來執行異步方法。

Controller

我們使用一個簡單的RestController完成異步的調用,如下所示:

@SpringBootApplication
@RestController
@EnableAsync
@Slf4j
public class SpringAsyncApplication {
 @Autowired
 private BusyService busyService;
 public static void main(String[] args) {
 SpringApplication.run(SpringAsyncApplication.class, args);
 }
 @RequestMapping("test")
 public String test() throws InterruptedException, ExecutionException {
 CompletableFuture<String> jane = busyService.busyMethod("Jane");
 CompletableFuture<String> allen = busyService.busyMethod("Allen");
 CompletableFuture<String> james = busyService.busyMethod("James");
 CompletableFuture.allOf(jane,allen,james).join();
 log.info(jane.get());
 log.info(allen.get());
 log.info(james.get());
 return "success";
 }
 @Bean
 public Executor taskExecutor() {
 ……
 }
}

  

我們在啟動類上加上@EnableAsync注解,使得Spring-Boot可以使用異步調用。再看看test()方法,我們調用了3次異步方法,並等待它們全部完成后,將它們打印出來。我們啟動項目,並在瀏覽器中訪問這個方法,地址是:http://localhost:8080/test。

如何使用Spring的Async注解創建異步方法

 

我們在等待了5秒后,頁面上返回了“success”。我們再看看后台打印的結果:

如何使用Spring的Async注解創建異步方法

 

我們看到名字前綴為“Java同學會”前綴的3個線程,打印了busyMethod方法中的日志。因為busyMethod方法是我們定義的Executor線程池中的線程執行的。我們再看看test方法和busyMethod方法中日志打印的時間,它們相隔了5秒,說明test方法中的CompletableFuture.allOf(jane,allen,james).join()一直在等待,等待所有調用的異步方法都執行完,才繼續執行。

好了,Spring的@Async就介紹完了,是不是很方便呢?有問題評論區留言哦~~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM