前言
之前連續(xù)寫了幾篇關于使用@Async實現(xiàn)異步調(diào)用的內(nèi)容,也得到不少童鞋的反饋,其中問題比較多的就是關于返回Future的使用方法以及對異步執(zhí)行的超時控制,所以這篇就來一起講講這兩個問題的處理。
如果您對于@Async注解的使用還不了解的話,可以看看之前的文章,具體如下:
定義異步任務
首先,我們先使用@Async注解來定義一個異步任務,這個方法返回Future類型,具體如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@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任務的執(zhí)行結果進行取消、查詢是否完成、獲取結果的接口。必要時可以通過get方法獲取執(zhí)行結果,該方法會阻塞直到任務返回結果。
它的接口定義如下:
1
2
3
4
5
6
7
8
|
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。參數(shù)mayInterruptIfRunning表示是否允許取消正在執(zhí)行卻沒有執(zhí)行完畢的任務,如果設置true,則表示可以取消正在執(zhí)行過程中的任務。如果任務已經(jīng)完成,則無論mayInterruptIfRunning為true還是false,此方法肯定返回false,即如果取消已經(jīng)完成的任務會返回false;如果任務正在執(zhí)行,若mayInterruptIfRunning設置為true,則返回true,若mayInterruptIfRunning設置為false,則返回false;如果任務還沒有執(zhí)行,則無論mayInterruptIfRunning為true還是false,肯定返回true。
- isCancelled方法表示任務是否被取消成功,如果在任務正常完成前被取消成功,則返回 true。
- isDone方法表示任務是否已經(jīng)完成,若任務完成,則返回true;
- get()方法用來獲取執(zhí)行結果,這個方法會產(chǎn)生阻塞,會一直等到任務執(zhí)行完畢才返回;
- get(long timeout, TimeUnit unit)用來獲取執(zhí)行結果,如果在指定時間內(nèi),還沒獲取到結果,就直接返回null。
也就是說Future提供了三種功能:
- 判斷任務是否完成;
- 能夠中斷任務;
- 能夠獲取任務執(zhí)行結果。
測試執(zhí)行與定義超時
在完成了返回Future的異步任務定義之后,我們來嘗試實現(xiàn)一個單元測試來使用這個Future完成任務的執(zhí)行,比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@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方法中還定義了該線程執(zhí)行的超時時間,通過執(zhí)行這個測試我們可以觀察到執(zhí)行時間超過5秒的時候,這里會拋出超時異常,該執(zhí)行線程就能夠因執(zhí)行超時而釋放回線程池,不至于一直阻塞而占用資源。
完整示例:
讀者可以根據(jù)喜好選擇下面的兩個倉庫中查看Chapter4-1-4項目:
Github:https://github.com/dyc87112/SpringBoot-Learning/
Gitee:https://gitee.com/didispace/SpringBoot-Learning/
總結
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:http://blog.didispace.com/springbootasync-4/