java中CompletableFuture的一些方法讲解

CompletableFuture类

能够异步去处理多任务

应用场景

存在IO密集型的任务可以选择CompletableFuture,IO部分交由另外一个线程去执行。

Logback、Log4j2异步日志记录的实现原理就是新起了一个线程去执行IO操作,这部分可以以CompletableFuture.runAsync(()->{ioOperation();})的方式去调用。

如果是CPU密集型就不推荐使用了推荐使用并行流

1.创建方法

1.1 new方式

 CompletableFuture<String> future1 = new CompletableFuture<>();

1.2 completedFuture()方式

通过CompletableFuture.completedFuture()方式

String message = "";
CompletableFuture<Object> future2 = CompletableFuture.completedFuture(message);

1.3 supplyAsync创建

通过CompletableFuture.supplyAsync创建

CompletableFuture.supplyAsync(() -> {} )

CompletableFuture.supplyAsync(() -> {} , threadPool)

区别:后者可以传入自定义的线程池 前者使用默认的ForkJoinPool

CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "" );

ExecutorService threadPool = Executors.newFixedThreadPool(4);
CompletableFuture<String> future4 = CompletableFuture.supplyAsync(() -> "" , threadPool);

1.4 runAsync创建

通过CompletableFuture.runAsync创建

CompletableFuture.runAsync(() -> {} )

CompletableFuture.runAsync(() -> {} , threadPool)

区别:后者可以传入自定义的线程池 前者使用默认的ForkJoinPool

CompletableFuture<Void> future5 = CompletableFuture.runAsync(()->{});

ExecutorService threadPool = Executors.newFixedThreadPool(4);
CompletableFuture<Void> future6 = CompletableFuture.runAsync(()->{} , threadPool);

runAsync 和 supplyAsync 的区别

supplyAsync :有返回值

runAsync : 无返回值

2.获取处理结果

2.1 get()

会等待CompletableFuture处理完成才获取结果

future4.get()

2.2 get(long timeout, TimeUnit unit)

如果在指定的时间内获取不到CompletableFuture的处理结果就抛出超时异常

TimeUnit.SECONDS : 为单位的意思 秒

future4.get(4, TimeUnit.SECONDS)

2.3 getNow(T valueIfAbsent)

立刻获取处理结果 如果未处理完成就返回自定义的值

T valueIfAbsent : 和CompletableFuture 的返回值对应

future4.getNow("fail")

2.4 join()

会等待CompletableFuture处理完成才获取结果

future4.join()

get 和 join 的区别

get : 需要用户手动抛出异常

join :用户不需要抛出异常

3.其它API(方法)介绍

3.1 whenComplete

对计算结果的处理

创建方式

以async结尾的方法将会在一个新的线程中执行组合操作

参数

BiConsumer : 定义对结果的处理

Executor : 自定义线程池

//方法一
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)
使用例子
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> 10/0);
CompletableFuture<Integer> cf2 = cf1.whenComplete((v, e) ->
                System.out.println(String.format("值:%s, 异常:%s", v, e)));
System.out.println(cf2.join());

3.2 thenApply

将前面计算结果的的CompletableFuture传递给thenApply,返回thenApply处理后的结果。

可以认为通过thenApply方法实现CompletableFuture<T>CompletableFuture<U>的转换。

白话一点就是将CompletableFuture的计算结果作为thenApply方法的参数,返回thenApply方法处理后的结果

创建方式

以async结尾的方法将会在一个新的线程中执行组合操作

参数

Function :对前一个CompletableFuture 计算结果的转化操作

Executor :自定义线程池

//方法一
public <U> CompletableFuture<U> thenApply(
    Function<? super T,? extends U> fn) {
    return uniApplyStage(null, fn);
}

//方法二
public <U> CompletableFuture<U> thenApplyAsync(
    Function<? super T,? extends U> fn) {
    return uniApplyStage(asyncPool, fn);
}

//方法三
public <U> CompletableFuture<U> thenApplyAsync(
    Function<? super T,? extends U> fn, Executor executor) {
    return uniApplyStage(screenExecutor(executor), fn);
}
使用例子
CompletableFuture<Integer> result = CompletableFuture
    .supplyAsync(其它API::randomInteger).thenApply((i) -> i * 8);
System.out.println(result.get());

说明:CompletableFuture先通过调用randomInteger方法获得值,然后把值作为thenApply中的参数进行*8。

3.3 thenAccept

thenApply 类似

区别就是 thenAccept 没有返回值

创建方式

以async结尾的方法将会在一个新的线程中执行组合操作

参数

Consumer : 对前一个CompletableFuture计算结果的操作

Executor : 自定义线程池

//方法一
public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
    return uniAcceptStage(null, action);
}

//方法二
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
    return uniAcceptStage(asyncPool, action);
}

//方法三
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
                                               Executor executor) {
    return uniAcceptStage(screenExecutor(executor), action);
}
使用例子
CompletableFuture.supplyAsync(其它API::getList)
                .thenAccept(strList -> strList.forEach(System.out::println));

说明:CompletableFuture调用getList获取集合 再把该结果传递给thenAccept进行处理打印。

3.4 thenCompose

异步结果流水化

将两个异步操作进行流水操作

简单来说就是一个异步操作后把处理结果给另一个异步去操作

创建方式

以async结尾的方法将会在一个新的线程中执行组合操作

参数

Function : 当前 CompletableFuture 计算结果的执行

Executor : 自定义线程池

//方法一
public <U> CompletableFuture<U> thenCompose(
    Function<? super T, ? extends CompletionStage<U>> fn) {
    return uniComposeStage(null, fn);
}

//方法二
public <U> CompletableFuture<U> thenComposeAsync(
    Function<? super T, ? extends CompletionStage<U>> fn) {
    return uniComposeStage(asyncPool, fn);
}

//方法三
public <U> CompletableFuture<U> thenComposeAsync(
    Function<? super T, ? extends CompletionStage<U>> fn,
    Executor executor) {
    return uniComposeStage(screenExecutor(executor), fn);
}
使用例子
CompletableFuture<Integer> result2 = CompletableFuture.supplyAsync(其它API::randomInteger)
                .thenCompose(i -> CompletableFuture.supplyAsync(() -> i * 10));
System.out.println(result2.get());

说明:CompletableFuture通过randomInteger获取到值 把值传递给thenCompose方法 thenCompose再开另一个异步去处理这个值

3.5 thenCombine

组合结果,将两个无关的CompletableFuture组合起来,第二个Completable并不依赖第一个Completable的结果

创建方式

以async结尾的方法将会在一个新的线程中执行组合操作

参数

CompletionStage : 新的CompletableFuture的计算结果

BiFunction :对两个CompletableFuture的结果进行处理

Executor : 自定义线程池

//方法一
public <U,V> CompletableFuture<V> thenCombine( 
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn) {
    return biApplyStage(null, other, fn);
}
//方法二
public <U,V> CompletableFuture<V> thenCombineAsync(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn) {
    return biApplyStage(asyncPool, other, fn);
}

//方法三
public <U,V> CompletableFuture<V> thenCombineAsync(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
    return biApplyStage(screenExecutor(executor), other, fn);
}
使用例子
CompletableFuture<Integer> result3 = CompletableFuture.supplyAsync(其它API::randomInteger)
                .thenCombine(CompletableFuture.supplyAsync(其它API::randomInteger), 
                             (i, j) -> i * j);
System.out.println(result3.get());

说明:CompletableFuture调用randomInteger获取值 在调用thenCombine,thenCombine开另一个CompletableFuture去获取另外一个值,这两个值同时交由thenCombine处理。

3.6 allOf

组合多个CompletableFuture

意思就是allOf会等待所有的CompletableFuture都执行了才会继续走下面的流程

所有的CompletableFuture都执行完后执行计算

allOf方法没有返回值,适合没有返回值并且需要前面所有任务执行完毕才能执行后续任务的应用场景

创建方式
//allOf
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
    return andTree(cfs, 0, cfs.length - 1);
}
使用例子
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("hello");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello";
});

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
           System.out.println("world");
           return "world";
});

CompletableFuture<Void> result4 = CompletableFuture.allOf(future1, future2);
System.out.println(result4.get() + " success");

说明:allOf会等待future1 和 future2都执行完成才会走下面的输出操作

3.7 anyOf

组合多个CompletableFuture

意思就是anyOf会等待只要有一个CompletableFuture执行了就会继续走下面的流程

任意一个CompletableFuture执行完后就会执行计算

该方法比较适合只要有一个返回值就可以继续执行其他任务的应用场景

创建方式
//anyOf
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
    return orTree(cfs, 0, cfs.length - 1);
}
使用例子
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            randomSleep();
            System.out.println("112121");
            return "11111111";});

CompletableFuture<String> future6 = CompletableFuture.supplyAsync(() -> {
            randomSleep();
            System.out.println("127777");
            return "222222222";});

CompletableFuture<Object> result8 = CompletableFuture.anyOf(future3, future6);
System.out.println(result8.get());

说明: 两个线程都会将结果打印出来,但是get方法只会返回最先完成任务的结果 。

注意事项

很多方法都提供了异步实现【带async后缀】,但是需小心谨慎使用这些异步方法

因为异步意味着存在上下文切换,可能性能不一定比同步好。

如果需要使用异步的方法,先做测试,用测试数据说话!!!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值