CompletableFuture

120 阅读3分钟

一、jdk1.5Future接口

1.1 接口方法

  1. Future接口提供了异步获取执行结果的方法get()
  2. 取消异步执行方法cancel()
  3. 异步获取执行结果,设定超时时间,超时报错get(long timeout,TimeUnit timeUnit)

1.2 Future接口的不足

  1. 不支持进一步非阻塞调用,在通过异步调用执行方法时,没有提供回调函数,只能一直阻塞等到任务完成
  2. 不支持链式调用
  3. 不支持多个异步结果合并
  4. 不支持异常处理
  5. 我们想要获取执行结果只能使用get()阻塞式调用,或者使用循环判断isDone()再调用get()方法获取结果,耗费CPU资源

二、CompletableFuture

JDK1.8之后新值一个提供了繁多方法的类CompletableFuture,其提供了很多扩展功能,支持异步获取执行结果、任务合并、对执行结果再异步消费、多任务顺序执行、速度比较消费快速的等方法

2.1 异步获取执行结果

  1. get():任务执行异常会抛出异常ExecutionException,阻塞等待过程被打断会抛出InterrputedException
  2. get(long timeout,TimeUnit unit),阻塞超时抛出TimeoutException
  3. getNow(T valueIfAbsent),立即获取执行结果,如果没有则传出传入的默认值
  4. join(),不抛出异常
  5. complete(),返回异步是否执行完毕,如果传入的默认值结果为false则代表已经执行完成,获取到的是异步执行结果,否则拿到的是传入的默认值

2.2 任务合并

public <U,V> CompletableFuture<V> thenCombine(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn) {
    return biApplyStage(null, other, fn);
}

用于两两任务完成后,将任务结果进行合并处理,先完成任务等待未完成任务执行结果

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 24, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1024));

    CompletableFuture<Integer> futureA = CompletableFuture.supplyAsync(() -> {
        return 25;
    }, poolExecutor);

    CompletableFuture<Integer> futureB = CompletableFuture.supplyAsync(() -> {
        return 50;
    }, poolExecutor);

    CompletableFuture<Integer> futureC = CompletableFuture.supplyAsync(() -> {
        return 75;
    }, poolExecutor);

    CompletableFuture<Integer> combine = futureA.thenCombine(futureB, (resA, resB) -> {
        return resA + resB;
    }).thenCombine(futureC, (resSum, resC) -> {
        return resSum + resC;
    });

    System.out.println(combine.get());
}

2.3 执行结果再异步消费

  1. thenRun(Runnable action),不关心前面任务的结果,也没有返回值
public static void main(String[] args) throws ExecutionException, InterruptedException {
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 24, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1024));

    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        return 125;
    }, poolExecutor);
    future.thenRun(() -> {
        System.out.println("执行后续逻辑");
    });
    poolExecutor.shutdown();
}
  1. thenAccept(Consumer action),接受前面的返回值,用于后续逻辑处理,处理完成不会有返回值
public static void main(String[] args) throws ExecutionException, InterruptedException {
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 24, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1024));

    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        return 125;
    }, poolExecutor);
    future.thenAccept(res -> {
        System.out.println("上一个程序执行结果为:" + res);
    });
    poolExecutor.shutdown();
    
}
  1. thenApply(Function fn),接受前面的返回值,后续处理完成之后,有返回值
public static void main(String[] args) throws ExecutionException, InterruptedException {
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 24, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1024));

    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        return 125;
    }, poolExecutor);
    CompletableFuture<Integer> returnFuture = future.thenApply(res -> {
        return res + 5;
    });
    System.out.println(returnFuture.get());
    poolExecutor.shutdown();

}

2.4 多任务顺序执行

我们使用thenCompose()用于处理那些需要顺序执行的任务

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 24, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1024));


    CompletableFuture<Integer> futureA = CompletableFuture.supplyAsync(() -> {
        System.out.println("执行任务A,返回结果:" + 50);
        return 50;
    }, poolExecutor);

    futureA.thenCompose(res -> {
        return CompletableFuture.supplyAsync(() -> {
            System.out.println("执行任务B,增加值:" + 75);
            return 75 + res;
        });
    }).whenComplete((res, ex) -> System.out.println(res));

    poolExecutor.shutdown();
}

2.5 任务速度比较,消费速度快的

public <U> CompletableFuture<U> applyToEither(
    CompletionStage<? extends T> other, Function<? super T, U> fn) {
    return orApplyStage(null, other, fn);
}

代码示例

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 24, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1024));


    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("执行程序A,返回50");
        return 50;
    }, poolExecutor);

    CompletableFuture<Integer> futureB = CompletableFuture.supplyAsync(() -> {
        System.out.println("程序B开始执行,返回75");
        return 75;
    }, poolExecutor);

    future.applyToEither(futureB, res -> {
        System.out.println("最终执行结果:" + res);
        return res;
    });

    poolExecutor.shutdown();
}