在开发中会碰到一种场景,如下
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异步调用。