可兼容未来电源异步

2022-09-01 21:19:46

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

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

有谁知道他们为什么选择使用接口供应商?使用 Callable 不是更自然吗,这是 Runnable 返回一个值的类比?这是因为供应商不会引发无法处理的异常吗?


答案 1

简短的回答

不,在 中使用它并不更自然。这个论点几乎完全是关于语义的,所以如果你事后仍然感到不相信,那也没关系。CallableSupplierCompletableFuture.supplyAsync

长答案

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

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

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

该接口类似于 ,因为两者都是为实例可能由另一个线程执行的类设计的。CallableRunnable

供应商是作为包装的一部分创建的。该软件包是上述Java 8中更改的一个组成部分。它提供了可由 lambda 表达式和方法引用作为目标的常见函数类型。java.util.function

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

那么,为什么是供应商而不能调用呢

CompletableFuture是受 Java 8 中上述更改启发的包中添加内容的一部分,它允许开发人员以功能性的、隐式可并行化的方式构造其代码,而不是显式处理其中的并发性。java.util.concurrent

它的方法需要一种方法来提供特定类型的结果,并且它更感兴趣的是这个结果,而不是为了达到这个结果而采取的行动。它也不一定关心异常完成(另请参阅下面的“关于...”段落)。supplyAsync

尽管如此,如果 Runnable 用于无参数、无结果的功能接口,那么 Callable 难道不应该用于无参数、单结果功能接口吗?

不一定。

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

那么可以由Callable.call() 引发的已检查异常呢?

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

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

另一方面,A 是您用来提供某种类型的对象的函数。特殊情况不一定应作为.这是因为:SupplierSupplier

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

答案 2

推荐