CompletableFuture supplyAsync

时间:2016-03-28 05:09:43

标签: java concurrency java-8

我刚刚开始探索Java 8的一些并发功能。有一点让我感到困惑的是这两种静态方法:

CompletableFuture<Void> runAsync(Runnable runnable) 
CompletableFuture<U> supplyAsync(Supplier<U> supplier)

有谁知道他们选择使用界面供应商的原因?使用Callable是不是更自然,这是Runnable的类比,它返回​​一个值?这是因为供应商没有抛出无法处理的异常吗?

1 个答案:

答案 0 :(得分:11)

简短回答

不,在Callable中使用Supplier代替CompletableFuture.supplyAsync并不自然。这个论点几乎完全是关于语义的,所以如果你后来仍然不相信那就没关系。

答案很长

CallableSupplier功能接口/ SAM类型在功能上实际上是等效的(原谅双关语),但它们的来源和用途不同。

Callable 是作为java.util.concurrent包的一部分创建的。这个包在Java 8中围绕lambda表达式的巨大变化之前出现,最初集中在一系列帮助你编写并发代码的工具上,而不会偏离经典的多线程经典模型。

Callable的主要目的是抽象一个可以在不同的线程中执行并返回结果的动作。来自Callable的Javadoc:

  

Callable界面与Runnable类似,两者都是   设计用于其实例可能由其执行的类   另一个线程。

Supplier 是作为java.util.function包的一部分创建的。该包是Java 8中上述变化的组成部分。它提供了lambda表达式和方法引用可以作为目标的常用函数类型。

一个这样的类型是没有返回结果的参数的函数(即提供某种类型或Supplier函数的函数)。

那么为什么Supplier而不是Callable

CompletableFuturejava.util.concurrent包添加的一部分,它受到Java 8中上述变化的启发,允许开发人员以功能性,隐式可并行化的方式构建其代码,而不是明确地处理其中的并发。

它的supplyAsync方法需要一种方法来提供特定类型的结果,并且它对此结果更感兴趣,而不是为达到此结果而采取的操作。它也不一定关心特殊完成(另见下面的...... 段落。)

仍然,如果Runnable用于无参数,无结果功能接口,不应该Callable用于无参数,单结果功能接口?

不一定。

java.util.function中未包含对没有参数但未返回结果的函数的抽象(因此完全通过对外部上下文的副作用进行操作)。这意味着(有点烦人)Runnable用于需要这种功能接口的地方。

Exception可以抛出的已检查Callable.call()怎么办?

这是CallableSupplier之间预期语义差异的一个小标志。

Callable是一个可以在另一个线程中执行的动作,它允许您检查其执行后的副作用。如果一切顺利,您将得到特定类型的结果,但由于执行某些操作时会出现异常情况(特别是在多线程上下文中),您可能还需要定义和处理这种异常情况。

另一方面,Supplier是您依赖于提供某种类型对象的函数。特殊情况不应该成为Supplier的直接消费者的责任。这是因为:

  1. ...功能接口通常用于在多阶段流程中定义特定阶段以创建或变更数据,并且处理Exception可以是一个单独的阶段,以防您关心
  2. ...显式处理Exception会显着降低功能接口,lambda表达式和方法引用的表达能力