我刚刚开始探索Java 8的一些并发特性。让我有些困惑的是这两个静态方法:
CompletableFuture<Void> runAsync(Runnable runnable)
CompletableFuture<U> supplyAsync(Supplier<U> supplier)
有谁知道为什么选择使用界面供应商?使用Callable是否更自然,这类似于Runnable返回值?那是因为供应商没有抛出无法处理的异常吗?
简短答案
不,用Callable
代替Supplier
in
是不自然的CompletableFuture.supplyAsync
。该论点几乎完全是关于语义的,因此,如果您此后仍不确信,那就可以了。
长答案
的Callable
和Supplier
功能接口/ SAM类型在功能几乎等同(原谅双关语),但它们的起源和预期用途而不同。
Callable
是作为java.util.concurrent
软件包的一部分创建的。该程序包是在Java
8中的lambda表达式发生巨大变化之前进行的,最初集中在一系列工具上,这些工具可帮助您编写并发代码,而又不会偏离经典的动手多线程模型。
的主要目的Callable
是抽象一个可以在不同线程中执行并返回结果的动作。从Callable
的Javadoc:
该
Callable
接口与相似Runnable
,因为两者都是针对其实例可能由另一个线程执行的类设计的。
Supplier
是作为java.util.function
软件包的一部分创建的。该软件包是上述Java
8更改的组成部分。它提供了lambda表达式和方法引用可以作为目标的通用功能类型。
一种这样的类型是没有返回结果的参数的函数(即提供某种类型的Supplier
函数或函数)。
那么为什么Supplier
不Callable
呢?
CompletableFuture
是对该java.util.concurrent
软件包进行补充的一部分,该软件包的灵感来自于Java
8中的上述更改,并且允许开发人员以功能性,隐式可并行化的方式构造其代码,而不是显式地处理其中的并发。
它的supplyAsync
方法需要一种方法来提供特定类型的结果,并且它对该结果更感兴趣,而不是为达到该结果而采取的措施。它也不一定要关心出色的完成效果(另请参见下面的
“关于…的内容” 部分)。
仍然,如果Runnable
用于无参数,无结果的功能接口,是否不Callable
应该用于无参数,无结果的功能接口?
不必要。
没有参数且不返回结果(因此完全通过外部上下文的副作用进行操作)的函数的抽象未包含在中java.util.function
。这意味着Runnable
在需要这种功能接口的任何地方都使用(有些令人讨厌)。
怎么样的检查Exception
可以通过抛出Callable.call()
?
这是Callable
和之间预期的语义差异的一个小标志Supplier
。
A
Callable
是可以在另一个线程中执行的操作,它使您可以检查其执行后的副作用。如果一切顺利,您将得到特定类型的结果,但是由于执行某些操作时可能会出现异常情况(尤其是在多线程上下文中),因此您可能还需要定义和处理此类异常情况。
Supplier
另一方面,A 是您提供某种类型的对象所依赖的功能。特殊情况不一定作为您的直接消费者承担责任Supplier
。这是因为:
Exception
s可以是一个单独的阶段,以防万一Exception
s会大大降低功能接口,lambda表达式和方法引用的表达能力