在JDK1.5已经提供了Future和Callable的实现,能够用于阻塞式获取结果,若是想要异步获取结果,一般都会以轮询的方式去获取结果,以下:编程
//定义一个异步任务 Future<String> future = executor.submit(()->{ Thread.sleep(2000); return "hello world"; }); //轮询获取结果 while (true){ if(future.isDone()) { System.out.println(future.get()); break; } }
从上面的形式看来轮询的方式会耗费无谓的CPU资源,并且也不能及时地获得计算结果.因此要实现真正的异步,上述这样是彻底不够的,在Netty中,咱们随处可见异步编程app
ChannelFuture f = serverBootstrap.bind(port).sync(); f.addListener(new GenericFutureListener<Future<? super Void>>() { @Override public void operationComplete(Future<? super Void> future) throws Exception { System.out.println("complete"); } });
而JDK1.8中的CompletableFuture
就为咱们提供了异步函数式编程,CompletableFuture
提供了很是强大的Future
的扩展功能,能够帮助咱们简化异步编程的复杂性,提供了函数式编程的能力,能够经过回调的方式处理计算结果,而且提供了转换和组合CompletableFuture
的方法。dom
CompletableFuture
提供了四个静态方法用来建立CompletableFuture对象:异步
public static CompletableFuture<Void> runAsync(Runnable runnable) public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
Asynsc
表示异步,而supplyAsync
与runAsync
不一样在与前者异步返回一个结果,后者是void.第二个函数第二个参数表示是用咱们本身建立的线程池,不然采用默认的ForkJoinPool.commonPool()
做为它的线程池.其中Supplier
是一个函数式接口,表明是一个生成者的意思,传入0个参数,返回一个结果.(更详细的能够看我另外一篇文章)ide
CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{ return "hello world"; }); System.out.println(future.get()); //阻塞的获取结果 ''helllo world"
如下4个方法用于获取结果函数式编程
//同步获取结果 public T get() public T get(long timeout, TimeUnit unit) public T getNow(T valueIfAbsent) public T join()
getNow
有点特殊,若是结果已经计算完则返回结果或者抛出异常,不然返回给定的valueIfAbsent值。join()
与get()
区别在于join()
返回计算的结果或者抛出一个unchecked异常(CompletionException),而get()
返回一个具体的异常.异步编程
public boolean complete(T value) public boolean completeExceptionally(Throwable ex)
上面方法表示当调用CompletableFuture.get()
被阻塞的时候,那么这个方法就是结束阻塞,而且get()
获取设置的value.函数
public static CompletableFuture<Integer> compute() { final CompletableFuture<Integer> future = new CompletableFuture<>(); return future; } public static void main(String[] args) throws Exception { final CompletableFuture<Integer> f = compute(); class Client extends Thread { CompletableFuture<Integer> f; Client(String threadName, CompletableFuture<Integer> f) { super(threadName); this.f = f; } @Override public void run() { try { System.out.println(this.getName() + ": " + f.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } new Client("Client1", f).start(); new Client("Client2", f).start(); System.out.println("waiting"); //设置Future.get()获取到的值 f.complete(100); //以异常的形式触发计算 //f.completeExceptionally(new Exception()); Thread.sleep(1000); }
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action) public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action) public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor) public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
上面4个方法是当计算阶段结束的时候触发,BiConsumer
有两个入参,分别表明计算返回值,另一个是异常.无返回值.方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其它的线程去执行(若是使用相同的线程池,也可能会被同一个线程选中执行)。this
future.whenCompleteAsync((v,e)->{ System.out.println("return value:"+v+" exception:"+e); });
public <U> CompletableFuture<U> handle(BiFunction<? super T,Throwable,? extends U> fn) public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn) public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn, Executor executor)
与whenComplete()
不一样的是这个函数返回CompletableFuture
并非原始的CompletableFuture
返回的值,而是BiFunction
返回的值.spa
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn) public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
它们与handle方法的区别在于handle方法会处理正常计算值和异常,所以它能够屏蔽异常,避免异常继续抛出。而thenApply方法只是用来处理正常值,所以一旦有异常就会抛出。
CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{ return "hello world"; }); CompletableFuture<String> future3 = future.thenApply((element)->{ return element+" addPart"; }).thenApply((element)->{ return element+" addTwoPart"; }); System.out.println(future3.get());//hello world addPart addTwoPart
只对CompletableFuture
的结果进行消费,无返回值,也就是最后的CompletableFuture
是void.
public CompletableFuture<Void> thenAccept(Consumer<? super T> action) public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)
//入参为原始的CompletableFuture的结果. CompletableFuture future4 = future.thenAccept((e)->{ System.out.println("without return value"); }); future4.get();
这个方法用来组合两个CompletableFuture
,其中一个CompletableFuture
等待另外一个CompletableFuture
的结果.
CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{ return "hello world"; }); CompletableFuture future5 = future.thenAcceptBoth(CompletableFuture.completedFuture("compose"), (x, y) -> System.out.println(x+y));//hello world compose
thenAcceptBoth
是当两个CompletableFuture
都计算完成,而咱们下面要了解的方法applyToEither
是当任意一个CompletableFuture计算完成的时候就会执行。
Random rand = new Random(); CompletableFuture<Integer> future9 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000 + rand.nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } return 100; }); CompletableFuture<Integer> future10 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000 + rand.nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } return 200; }); //两个中任意一个计算完成,那么触发Runnable的执行 CompletableFuture<String> f = future10.applyToEither(future9,i -> i.toString()); //两个都计算完成,那么触发Runnable的执行 CompletableFuture f1 = future10.acceptEither(future9,(e)->{ System.out.println(e); }); System.out.println(f.get());
若是想组合超过2个以上的CompletableFuture
,allOf
和anyOf
可能会知足你的要求.allOf
方法是当全部的CompletableFuture
都执行完后执行计算。anyOf
方法是当任意一个CompletableFuture
执行完后就会执行计算,计算的结果相同。
有了CompletableFuture
以后,咱们本身实现异步编程变得轻松不少,这个类也提供了许多方法来组合CompletableFuture
.结合Lambada表达式来用,变得很轻松.