古詩詞大全網 - 古詩大全 - SpringBoot之@Async異步調用

SpringBoot之@Async異步調用

利用 Spring Initializer 創建壹個 gradle 項目 spring-boot-async-task,創建時添加相關依賴。

在 Spring Boot 入口類上配置 @EnableAsync 註解開啟異步處理。

創建任務抽象類 AbstractTask,並分別配置三個任務方法 doTaskOne(),doTaskTwo(),doTaskThree()。

下面通過壹個簡單示例來直觀的理解什麽是同步調用:

定義 Task 類,繼承 AbstractTask,三個處理函數分別模擬三個執行任務的操作,操作消耗時間隨機取(10 秒內)。

在 單元測試 用例中,註入 Task 對象,並在測試用例中執行 doTaskOne(),doTaskTwo(),doTaskThree() 三個方法。

執行單元測試,可以看到類似如下輸出:

任務壹、任務二、任務三順序的執行完了,換言之 doTaskOne(),doTaskTwo(),doTaskThree() 三個方法順序的執行完成。

上述的可以看到 執行時間比較長,若這三個任務本身之間 不存在依賴關系,可以 並發執行 的話,同步調用在 執行效率 方面就比較差,可以考慮通過 異步調用 的方式來 並發執行。

創建 AsyncTask類,分別在方法上配置 @Async 註解,將原來的 同步方法 變為 異步方法。

在 單元測試 用例中,註入 AsyncTask 對象,並在測試用例中執行 doTaskOne(),doTaskTwo(),doTaskThree() 三個方法。

執行單元測試,可以看到類似如下輸出:

如果反復執行單元測試,可能會遇到各種不同的結果,比如:

原因是目前 doTaskOne(),doTaskTwo(),doTaskThree() 這三個方法已經 異步執行 了。主程序在 異步調用 之後,主程序並不會理會這三個函數是否執行完成了,由於沒有其他需要執行的內容,所以程序就 自動結束 了,導致了 不完整 或是 沒有輸出任務 相關內容的情況。

根據業務需求,可以將暫時不需要立即獲得處理的方法設置為 @Async .

比如用戶在前端點擊完成了登錄操作,這時候根據業務要求需要在登錄成功之後進行埋點的處理.

其實埋點成功與否都不影響用戶操作,這時候就可以將埋點方法設置為@Async.

個人認為此類任務通常有三個特征:

為了讓 doTaskOne(),doTaskTwo(),doTaskThree() 能正常結束,假設我們需要統計壹下三個任務 並發執行 ***耗時多少,這就需要等到上述三個函數都完成動用之後記錄時間,並計算結果。

那麽我們如何判斷上述三個 異步調用 是否已經執行完成呢?我們需要使用 Future<T> 來返回 異步調用 的 結果。

在 單元測試 用例中,註入 AsyncCallBackTask 對象,並在測試用例中執行 doTaskOneCallback(),doTaskTwoCallback(),doTaskThreeCallback() 三個方法。循環調用 Future 的 isDone() 方法等待三個 並發任務 執行完成,記錄最終執行時間。

在測試用例壹開始記錄開始時間;在調用三個異步函數的時候,返回Future類型的結果對象;在調用完三個異步函數之後,開啟壹個循環,根據返回的Future對象來判斷三個異步函數是否都結束了。若都結束,就結束循環;若沒有都結束,就等1秒後再判斷。跳出循環之後,根據結束時間 - 開始時間,計算出三個任務並發執行的總耗時。

執行壹下上述的單元測試,可以看到如下結果:

可以看到,通過 異步調用,讓任務壹、任務二、任務三 並發執行,有效的 減少 了程序的 運行總時間。

在上述操作中,創建壹個 線程池配置類 TaskConfiguration ,並配置壹個 任務線程池對象 taskExecutor。

上面我們通過使用 ThreadPoolTaskExecutor 創建了壹個 線程池,同時設置了以下這些參數:

創建 AsyncExecutorTask類,三個任務的配置和 AsyncTask 壹樣,不同的是 @Async 註解需要指定前面配置的 線程池的名稱 taskExecutor。

在 單元測試 用例中,註入 AsyncExecutorTask 對象,並在測試用例中執行 doTaskOne(),doTaskTwo(),doTaskThree() 三個方法。

執行壹下上述的 單元測試,可以看到如下結果:

執行上面的單元測試,觀察到 任務線程池 的 線程池名的前綴 被打印,說明 線程池 成功執行 異步任務!

解決方案如下,重新設置線程池配置對象,新增線程池 setWaitForTasksToCompleteOnShutdown() 和 setAwaitTerminationSeconds() 配置: