java8 CompletableFuture

阅读数:82 评论数:0

跳转到新版页面

分类

python/Java

正文

在JAVA5已经提供了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资源,而且也不能及时得到计算结果,在JAVA8中CompletableFuture提供了更强大的Future扩展功能。

创建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)

supplyAsync与runAsync不同在于前者异步返回一个结果,后者是void,第二个参数表示使用我们自己创建的线程,否则采用默认的ForkJoinPool.commonPool()作为它的线程池,其中Supplier是一个函数式接口(所以可以使用lamda写法),传入0个参数,返回 一个结果。

CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{
            return "hello world";
  });
System.out.println(future.get());  //阻塞的获取结果  ''helllo world"

主动计算

以下方法用于获取结果

//同步获取结果
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)

主动调用上面的方法,可以结束获取结果时的阻塞。

计算结果完成时的处理

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)
// 处理task的异常
public CompletableFuture<T>     exceptionally(Function<Throwable,? extends T> fn)

以上方法是当计算结束的时候触发,BiConsumer有两个入参,分别代表计算返回值,另外一个是异常。无返回值的方法不以Async结尾。

// 两个参数,task结果和task异常
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返回的值。

CompletableFuture的组合

1、thenApply

当计算结算完成之后,后面可以继续一系列的thenApply,来完成值的转化。

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方法只是用来处理正常值,因此一旦有异常就会抛出。

2、thenAccept

只对CompletableFuture的结果进行消费,不返回值。

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)

 

3、thenAcceptBoth

这个方法用来等待另一个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

4、either和all

(1)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)allOf方法是当所有的CompletableFuture都执行完成后执行计算

(3)anyOf是当任意一个CompletableFuture执行完成后会执行计算

 




相关推荐

修饰接口中默认的方法实现(也就是接口中可以包含方法体,这打破了Java之前版本对接口的语法限制)。 public int

一、概述 1、lambda允许把函数作为一个方法的参数。 二、取代某些匿名内部类 1、无参数函数的简写 如果需要创建一个线程,一种常见的写法是这样: // JDK7 匿名内部类写法 new Threa

作用:使代码更简洁。 有些情况下,我们用lambda表达式仅仅是调用一些已经存在的方法,除了调用动作外,没有其他任何多余的动作,而通过方法引用可以使代码更简洁、更容易理解。 类型 语法 对应的L

一、概述 如果没有终端操作,中间操作是不会得到执行的(惰性求值)。 stream的使用可以将代码中大量的for循环变为简单的链式函数操作,但是需要注意性能,在数据量小的情况下二都相差不多,但是在数据

Supplier接口是JAVA8以后配合lambda表达式和函数式接口编程(FunctionInterface,以下简称FI)组合使用的一个接口。它最适合于表示工厂,简而言之,Supplier&

一、函数式编程和非函数编程的区别 (1)函数式编程:先考虑传入的参数,再考虑方法的实现。 (2)非函数编程:先定义好方法,再传入指定的参数 二、何为函数式接口 函数式接口(Functional Int

java8时,java.util.concurrent.atomic包中提供了一个新的原子类LongAddr,提供了原子累计值的方法,在高并发的场景下它比Ato

一、Java8简介 1、添加了函数式编程、Stream、全新的日期处理类。 2、函数编程新加了一些概念:lambda表达式、函数式接口、函数引用、默认方法、Optional类(干掉空指针)等。 3、S

一、概述 Java8引入了@Contented这个新的注解来减少伪共享(False Sharing)的发生。 二、伪共享 1、缓存行 CPU读取内存数据时并非一次只读一个字节,而是会读一段64字节长度

一、概述 Collectors是java.util.stream包下的一个工具类,其中各个方法的返回值可以作为java.util.stream.Stream#collect的入参,实现对队列的各种操作