Java 直接使用Spring@Async与CompletableFuture相比有什么优势?

Java 直接使用Spring@Async与CompletableFuture相比有什么优势?,java,spring,asynchronous,java-8,completable-future,Java,Spring,Asynchronous,Java 8,Completable Future,使用与仅返回CompletableFuture的优点是什么 您的应用程序由容器管理。由于不鼓励自己生成线程s,因此可以让容器注入托管执行器 @Service class MyService { @Autowired private Executor executor; public CompletableFuture<?> compute() { return CompletableFuture.supplyAsync(() -> /* compute v

使用与仅返回
CompletableFuture
的优点是什么

您的应用程序由容器管理。由于不鼓励自己生成
线程
s,因此可以让容器注入托管
执行器

@Service
class MyService {
  @Autowired
  private Executor executor;

  public CompletableFuture<?> compute() {
    return CompletableFuture.supplyAsync(() -> /* compute value */, executor);
  }
}
@服务
类MyService{
@自动连线
私人遗嘱执行人;
公共CompletableFuture compute(){
返回CompletableFuture.SupplySync(()->/*计算值*/,执行器);
}
}
两者之间没有“对”:它们是互补的技术:

  • CompletableFuture
    提供了一种方便的方式来链接异步计算的不同阶段,比Spring的
    ListenableFuture
    更具灵活性
  • @Async
    为您的后台任务和线程提供方便的管理,并为您的执行器提供标准的Spring配置
但两者可以结合()。假设要将以下方法转换为后台任务,返回一个
CompletableFuture

public String compute() {
    // do something slow
    return "my result";
}
你必须做的是:

  • 如果尚未完成:使用
    @EnableAsync
    执行器
    bean配置应用程序
  • @Async
  • 将其结果包装到
    CompletableFuture.completedFuture()
@Async
公共CompletableFuture computeAsync(){
//做点慢动作-不要改变这部分
//注意:无需将代码包装在lambda/方法引用中,
//不必为遗嘱执行人的处理而烦恼
返回CompletableFuture.completedFuture(“我的结果”);
}

正如您所注意到的,您不必费心将后台任务提交给执行者:Spring会为您处理这些。您只需将结果包装成一个已完成的
CompletableFuture
,以便签名符合调用方的期望。

可能会对您有所帮助。这在java 8之前的版本中可能是有意义的。但是CompletableFuture在默认情况下会分叉到分叉连接池中。您拥有一个托管环境。不鼓励您自己生成线程,但如果必须这样做,那么您可以将
CompletableFuture
与注入的
ExecutorService
一起使用,该服务应由您的容器管理。将其作为一个答案提供,如果您获得了支持,我们就来看看。我不认为这是一种比公认答案中的更好的方法。那里没有那么神奇。我遗漏了什么?@BalázsNémeth,不确定你正在用“那里的魔法更少”重新填充哪一个,但我认为它是公认答案中的一个。事实上,如果你不喜欢魔术,像往常一样,编程版本会更适合你。然而,人们通常认为声明性编程更好,这是使用Spring的代码> @ AsYNC/<代码>时的情况。当然,这需要一些“魔法”;)我明白你的意思@异步是一个更高级别的概念。我可能应该相信它,但我不知何故不相信:)@BalázsNémeth我特别欣赏
@Async
的一点是,您不必指定执行器,但仍然可以通过Spring的
@enablesync
配置对其进行自定义。使用
supplyAsync()
,要么使用公共F-J池(可能不需要),要么每次使用时都必须传递executor参数。
@Async
public CompletableFuture<String> computeAsync() {
    // do something slow - no change to this part
    // note: no need to wrap your code in a lambda/method reference,
    //       no need to bother about executor handling
    return CompletableFuture.completedFuture("my result");
}