在開發中會碰到一種場景,如下
Object result1 = service1.func1();//執行80ms Object result2 =service2.func2();//執行50ms service3.func3(result1,result2);
func3()需要等待func1和func2的執行結果。總共需要等待130ms.如果能夠讓func1和func2同時執行,那么最少的等待時間將會是80ms.
下面使用CompletableFuture來實現。
JDK1.8才新加入的一個實現類CompletableFuture
,實現了Future<T>
, CompletionStage<T>
兩個接口。
定義任務類
這里定義了一個方法findUser,它的返回值是CompletableFuture<String>,用來模擬遠程調用。
當執行結果是正常時,通過
public boolean complete(T value)
返回結果。
當執行異常時,如果想向調用者返回異常,通過
public boolean completeExceptionally(Throwable ex)
返回異常。
class TaskService{ public CompletableFuture<String> findUser(){ CompletableFuture<String> future = new CompletableFuture(); //模仿遠程調用線程 new Thread(){ @Override public void run() { String result = null; System.out.println("任務開始執行...."); try{ Thread.sleep(3000); //模仿RPC遠程調用 result = rpcRequest(true); System.out.println("任務執行結束...."); } catch(Exception ex){ future.completeExceptionally(ex); } future.complete(result); } }.start(); 直接返回future. return future; } /** *功能描述 * @author lgj * @Description 模仿RPC遠程調用 * @date 4/29/19 * @param: flag true:返回正常結果 false:拋出異常 * * @return: * */ public String rpcRequest(boolean flag){ String result = null; if(flag){ result = "libai"; } else { throw new NullPointerException(); } return result; } }
主線程調用
public class CompletableFutureDemo { public static void main(String args[]){ TaskService service = new TaskService(); CompletableFuture<String> future = service.findUser(); future.whenComplete((t,u)->{ if(u != null){ System.out.println("異步調用發生異常:" + u); } else { System.out.println("異步調用執行正常: " + t); } }); System.out.println("主線程任務執行完畢"); } }
主線程通過whenComplete來回調結果。這里需要通過lambada 表達式來獲取結果
public CompletableFuture<T> whenComplete( BiConsumer<? super T, ? super Throwable> action) { return uniWhenCompleteStage(null, action); }
當結果正常時
任務開始執行....
主線程任務執行完畢
任務執行結束....
異步調用執行正常: libai
當調用發生異常時
任務開始執行....
主線程任務執行完畢
異步調用發生異常:java.lang.NullPointerException
以上,便實現了異步調用。
目前,dubbo-2.7.0+便是使用CompletableFuture來實現rpc異步調用。