一尘不染

CompletableFuture supplyAsync

java

我刚刚开始探索Java 8的一些并发特性。让我有些困惑的是这两个静态方法:

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

有谁知道为什么选择使用界面供应商?使用Callable是否更自然,这类似于Runnable返回值?那是因为供应商没有抛出无法处理的异常吗?


阅读 201

收藏
2020-12-03

共1个答案

一尘不染

简短答案

不,用Callable代替Supplierin
是不自然的CompletableFuture.supplyAsync。该论点几乎完全是关于语义的,因此,如果您此后仍不确信,那就可以了。

长答案

CallableSupplier功能接口/ SAM类型在功能几乎等同(原谅双关语),但它们的起源和预期用途而不同。

Callable 是作为java.util.concurrent软件包的一部分创建的。该程序包是在Java
8中的lambda表达式发生巨大变化之前进行的,最初集中在一系列工具上,这些工具可帮助您编写并发代码,而又不会偏离经典的动手多线程模型。

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

Callable接口与相似Runnable,因为两者都是针对其实例可能由另一个线程执行的类设计的。

Supplier 是作为java.util.function软件包的一部分创建的。该软件包是上述Java
8更改的组成部分。它提供了lambda表达式和方法引用可以作为目标的通用功能类型。

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

那么为什么SupplierCallable呢?

CompletableFuture是对该java.util.concurrent软件包进行补充的一部分,该软件包的灵感来自于Java
8中的上述更改,并且允许开发人员以功能性,隐式可并行化的方式构造其代码,而不是显式地处理其中的并发。

它的supplyAsync方法需要一种方法来提供特定类型的结果,并且它对该结果更感兴趣,而不是为达到该结果而采取的措施。它也不一定要关心出色的完成效果(另请参见下面的
“关于…的内容” 部分)。

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

不必要。

没有参数且不返回结果(因此完全通过外部上下文的副作用进行操作)的函数的抽象未包含在中java.util.function。这意味着Runnable在需要这种功能接口的任何地方都使用(有些令人讨厌)。

怎么样的检查Exception可以通过抛出Callable.call()

这是Callable和之间预期的语义差异的一个小标志Supplier

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

Supplier另一方面,A 是您提供某种类型的对象所依赖的功能。特殊情况不一定作为您的直接消费者承担责任Supplier。这是因为:

  1. …功能接口通常用于定义多阶段过程中的特定阶段,以创建或更改数据,并且处理Exceptions可以是一个单独的阶段,以防万一
  2. …显式处理Exceptions会大大降低功能接口,lambda表达式和方法引用的表达能力
2020-12-03