CompletableFuture用法详解

前言

JAVA支持的多线程开启方式

根据Oracle官方出具的Java文档说明,创建线程的方式只有两种:继承Thread或者实现Runnable接口。 但是这两种方法都存在一个缺陷,没有返回值,也就是说我们无法得知线程执行结果。虽然简单场景下已经满足,但是当我们需要返回值的时候怎么办呢? Java 1.5 以后的Callable和Future接口就解决了这个问题,我们可以通过向线程池提交一个Callable来获取一个包含返回值的Future对象,从此,我们的程序逻辑就不再是同步顺序。

Future接口的局限性

当我们得到包含结果的Future时,我们可以使用get方法等待线程完成并获取返回值,注意我加粗的地方,Future的get() 方法会阻塞主线程。 Future文档原文如下

A {@code Future} represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation.

谷歌翻译:

{@code Future}代表异步*计算的结果。提供了一些方法来检查计算是否完成,等待其完成并检索计算结果

Future执行耗时任务

当Future的线程进行了一个非常耗时的操作,那我们的主线程也就阻塞了。 当我们在简单业务上,可以使用Future的另一个重载方法get(long,TimeUnit)来设置超时时间,避免我们的主线程被无穷尽地阻塞。 不过,有没有更好的解决方案呢?

我们需要更强大异步能力

不仅如此,当我们在碰到一下业务场景的时候,单纯使用Future接口或者FutureTask类并不能很好地完成以下我们所需的业务

  • 将两个异步计算合并为一个,这两个异步计算之间相互独立,同时第二个又依赖于第一个的结果
  • 等待Future集合种的所有任务都完成。
  • 仅等待Future集合种最快结束的任务完成(有可能因为他们试图通过不同的方式计算同一个值),并返回它的结果。
  • 通过编程方式完成一个Future任务的执行(即以手工设定异步操作结果的方式)。
  • 应对Future的完成时间(即当Future的完成时间完成时会收到通知,并能使用Future的计算结果进行下一步的的操作,不只是简单地阻塞等待操作的结果)

正文

神奇的CompletableFuture

什么是CompletableFuture

在Java 8中, 新增加了一个包含50个方法左右的类: CompletableFuture,结合了Future的优点,提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合CompletableFuture的方法。

CompletableFuture被设计在Java中进行异步编程。异步编程意味着在主线程之外创建一个独立的线程,与主线程分隔开,并在上面运行一个非阻塞的任务,然后通知主线程进展,成功或者失败。

通过这种方式,你的主线程不用为了任务的完成而阻塞/等待,你可以用主线程去并行执行其他的任务。 使用这种并行方式,极大地提升了程序的表现

当一个Future可能需要显示地完成时,使用CompletionStage接口去支持完成时触发的函数和操作。
当2个以上线程同时尝试完成、异常完成、取消一个CompletableFuture时,只有一个能成功。

CompletableFuture实现了CompletionStage接口的如下策略:

1.为了完成当前的CompletableFuture接口或者其他完成方法的回调函数的线程,提供了非异步的完成操作。

2.没有显式入参Executor的所有async方法都使用ForkJoinPool.commonPool()为了简化监视、调试和跟踪,
    所有生成的异步任务都是标记接口AsynchronousCompletionTask的实例。

3.所有的CompletionStage方法都是独立于其他共有方法实现的,因此一个方法的行为不会受到子类中其他
    方法的覆盖。

CompletableFuture实现了Futurre接口的如下策略:

1.CompletableFuture无法直接控制完成,所以cancel操作被视为是另一种异常完成形式。
    方法isCompletedExceptionally可以用来确定一个CompletableFuture是否以任何异常的方式完成。

2.以一个CompletionException为例,方法get()和get(long,TimeUnit)抛出一个ExecutionException,
    对应CompletionException。为了在大多数上下文中简化用法,这个类还定义了方法join()和getNow,
    而不是直接在这些情况中直接抛出CompletionException。

CompletableFuture API

实例化CompletableFuture

实例化方式

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);

public static CompletableFuture<Void> runAsync(Runnable runnable);
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);

有两种格式,一种是supply开头的方法,一种是run开头的方法

  • supply开头:这种方法,可以返回异步线程执行之后的结果
  • run开头:这种不会返回结果,就只是执行线程任务

或者可以通过一个简单的无参构造器

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

小贴士:我们注意到,在实例化方法中,我们是

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值