Spring Boot使用@Async實現非同步呼叫返回結果:使用Future以及定義超時
關於使用 @Async
實現非同步呼叫的內容,也得到不少童鞋的反饋,其中問題比較多的就是關於返回 Future
的使用方法以及對非同步執行的超時控制,所以這篇就來一起講講這兩個問題的處理。
如果您對於 @Async
註解的使用還不瞭解的話,可以看看之前的文章,具體如下:
定義非同步任務
首先,我們先使用 @Async
註解來定義一個非同步任務,這個方法返回 Future
型別,具體如下:
-
@Slf4j
-
@Component
-
public class Task {
-
public static Random random = new Random();
-
@Async("taskExecutor")
-
public Future<String> run() throws Exception {
-
long sleep = random.nextInt(10000);
-
log.info("開始任務,需耗時:" + sleep + "毫秒");
-
Thread.sleep(sleep);
-
log.info("完成任務");
-
return new AsyncResult<>("test");
-
}
-
}
Tips:什麼是 Future
型別?
Future
是對於具體的 Runnable
或者 Callable
任務的執行結果進行取消、查詢是否完成、獲取結果的介面。必要時可以通過get方法獲取執行結果,該方法會阻塞直到任務返回結果。
它的介面定義如下:
-
public interface Future<V> {
-
boolean cancel(boolean mayInterruptIfRunning);
-
boolean isCancelled();
-
boolean isDone();
-
V get() throws InterruptedException, ExecutionException;
-
V get(long timeout, TimeUnit unit)
-
throws InterruptedException, ExecutionException, TimeoutException;
-
}
它宣告這樣的五個方法:
-
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提供了三種功能:
-
判斷任務是否完成;
-
能夠中斷任務;
-
能夠獲取任務執行結果。
測試執行與定義超時
在完成了返回 Future
的非同步任務定義之後,我們來嘗試實現一個單元測試來使用這個Future完成任務的執行,比如:
-
@Slf4j
-
@RunWith(SpringJUnit4ClassRunner.class)
-
@SpringBootTest
-
public class ApplicationTests {
-
@Autowired
-
private Task task;
-
@Test
-
public void test() throws Exception {
-
Future<String> futureResult = task.run();
-
String result = futureResult.get(5, TimeUnit.SECONDS);
-
log.info(result);
-
}
-
}
上面的程式碼中,我們在get方法中還定義了該執行緒執行的超時時間,通過執行這個測試我們可以觀察到執行時間超過5秒的時候,這裡會丟擲超時異常,該執行執行緒就能夠因執行超時而釋放回執行緒池,不至於一直阻塞而佔用資源。
完整示例:
讀者可以根據喜好選擇下面的兩個倉庫中檢視 Chapter4-1-5
專案:
-
Github:https://github.com/dyc87112/SpringBoot-Learning/
-
Gitee:https://gitee.com/didispace/SpringBoot-Learning/
如果您對這些感興趣,歡迎star、follow、收藏、轉發給予支援!
熱文推薦: