Spring Boot使用@Async實現異步調用返回結果:使用Future以及定義超時

關於使用 @Async實現異步調用的內容,也得到不少童鞋的反饋,其中問題比較多的就是關於返回 Future的使用方法以及對異步執行的超時控制,所以這篇就來一起講講這兩個問題的處理。

 

如果您對於 @Async註解的使用還不瞭解的話,可以看看之前的文章,具體如下:

定義異步任務

首先,我們先使用 @Async註解來定義一個異步任務,這個方法返回 Future類型,具體如下:


 
  1. @Slf4j

  2. @Component

  3. public class Task {

  4.  

  5.    public static Random random = new Random();

  6.  

  7.    @Async("taskExecutor")

  8.    public Future<String> run() throws Exception {

  9.        long sleep = random.nextInt(10000);

  10.        log.info("開始任務,需耗時:" + sleep + "毫秒");

  11.        Thread.sleep(sleep);

  12.        log.info("完成任務");

  13.        return new AsyncResult<>("test");

  14.    }

  15.  

  16. }

Tips:什麼是 Future類型?

Future是對於具體的 Runnable或者 Callable任務的執行結果進行取消、查詢是否完成、獲取結果的接口。必要時可以通過get方法獲取執行結果,該方法會阻塞直到任務返回結果。

它的接口定義如下:


 
  1. public interface Future<V> {

  2.    boolean cancel(boolean mayInterruptIfRunning);

  3.    boolean isCancelled();

  4.    boolean isDone();

  5.    V get() throws InterruptedException, ExecutionException;

  6.    V get(long timeout, TimeUnit unit)

  7.        throws InterruptedException, ExecutionException, TimeoutException;

  8. }

它聲明這樣的五個方法:

  • cancel方法用來取消任務,如果取消任務成功則返回true,如果取消任務失敗則返回false。參數mayInterruptIfRunning表示是否允許取消正在執行卻沒有執行完畢的任務,如果設置true,則表示可以取消正在執行過程中的任務。如果任務已經完成,則無論mayInterruptIfRunning爲true還是false,此方法肯定返回false,即如果取消已經完成的任務會返回false;如果任務正在執行,若mayInterruptIfRunning設置爲true,則返回true,若mayInterruptIfRunning設置爲false,則返回false;如果任務還沒有執行,則無論mayInterruptIfRunning爲true還是false,肯定返回true。

  • isCancelled方法表示任務是否被取消成功,如果在任務正常完成前被取消成功,則返回 true。

  • isDone方法表示任務是否已經完成,若任務完成,則返回true;

  • get()方法用來獲取執行結果,這個方法會產生阻塞,會一直等到任務執行完畢才返回;

  • get(long timeout, TimeUnit unit)用來獲取執行結果,如果在指定時間內,還沒獲取到結果,就直接返回null。

也就是說Future提供了三種功能:

  1. 判斷任務是否完成;

  2. 能夠中斷任務;

  3. 能夠獲取任務執行結果。

測試執行與定義超時

在完成了返回 Future的異步任務定義之後,我們來嘗試實現一個單元測試來使用這個Future完成任務的執行,比如:


 
  1. @Slf4j

  2. @RunWith(SpringJUnit4ClassRunner.class)

  3. @SpringBootTest

  4. public class ApplicationTests {

  5.  

  6.    @Autowired

  7.    private Task task;

  8.  

  9.    @Test

  10.    public void test() throws Exception {

  11.        Future<String> futureResult = task.run();

  12.        String result = futureResult.get(5, TimeUnit.SECONDS);

  13.        log.info(result);

  14.    }

  15.  

  16. }

上面的代碼中,我們在get方法中還定義了該線程執行的超時時間,通過執行這個測試我們可以觀察到執行時間超過5秒的時候,這裏會拋出超時異常,該執行線程就能夠因執行超時而釋放回線程池,不至於一直阻塞而佔用資源。

完整示例:

讀者可以根據喜好選擇下面的兩個倉庫中查看 Chapter4-1-5項目:

  • Github:https://github.com/dyc87112/SpringBoot-Learning/

  • Gitee:https://gitee.com/didispace/SpringBoot-Learning/

如果您對這些感興趣,歡迎star、follow、收藏、轉發給予支持!

熱文推薦

理解使用 JWT 設計的單點登錄系統

全球最大同性交友網站 GitHub 10 歲了!

JDK 1.5 - 1.8 各版本的新特性總結

Spring Boot快速開發利器:Spring Boot CLI

IntelliJ IDEA 2018.1正式發佈!還能這麼玩?

消息中間件選型分析

 

其他推薦

從Spring-Session源碼看Session機制的實現細節

Spring Boot使用@Async實現異步調用:線程池的優雅關閉

Spring Boot使用@Async實現異步調用:自定義線程池

Spring Boot 2.0正式發佈,升還是不升呢?

Spring Boot 2.0 新特性概覽

Spring Boot/Cloud乾貨彙總

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章