【问题标题】:What would be the best approach to use CompletableFuture while running a stream of asynchronous tasks?在运行异步任务流时使用 CompletableFuture 的最佳方法是什么?
【发布时间】:2020-04-28 14:38:45
【问题描述】:

我有一个 Spring 组件 EventSvcFacade,它具有三个 EventValidationSvc 实现类实例的列表。这些类中的每一个都实现了方法boolean validate(T request),接受相同的输入,但在输入上调用不同的API,处理结果并返回一个布尔值。因此,该流程是为并发调用而设计的。我想出了两种从任务流中返回布尔值列表的方法。任何人都可以建议,在哪些因素上一种方法比另一种更好,或者还有其他更好的方法吗?

@Component
public class EventSvcFacade {

    @Autowired
    private List<EventValidationSvc<EventRequest>> validationSvcs;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    public List<Boolean> firstApproach(){
      final List<CompletableFuture<Boolean>> futures = validationSvcs.stream().map(service -> 
            CompletableFuture.supplyAsync(() -> service.validate(eventRequest), threadPoolExecutor))
            .collect(Collectors.toList());                                                                                      
      final List<Boolean> values = futures.stream().map(CompletableFuture :: 
            join).collect(Collectors.toList());
      return values;
    }

    public List<Boolean> secondApproach() {
      final List<Boolean> values = Collections.synchronizedList(new ArrayList<>());
      final CountDownLatch countDownLatch = new CountDownLatch(validationSvcs.size());
      validationSvcs.stream().forEach(service -> CompletableFuture.runAsync(() -> {         
            try{
             values.add(service.validate(eventRequest));
            }finally{
             countDownLatch.countDown();
            }
          }, threadPoolExecutor)
      );
      countDownLatch.await();
      return values;
   }
}

【问题讨论】:

  • 您的第二种方法不保持顺序。此外,它没有关于失败的反馈。它只会挂起。
  • 谢谢!所以除了调用 join() 或 get() 之外,没有办法通知主线程关于 CompletableFuture 中运行的任务的异常。
  • 当你用whenComplete链接一个动作或通过handle链接一个函数时,它也会在异常情况下被评估,获取异常作为参数,允许处理它。

标签: java multithreading java-8 concurrency completable-future


【解决方案1】:

第一种方法更简洁,因为它是pure:因为它不依赖副作用,所以更容易推理并且在以后修改代码时不太可能中断。

此外,第一种方法不依赖于 ad-hoc 同步结构,例如第二种方法对 CountDownLatch 实例所做的那样。如果您的先决条件发生变化并且只有两个服务可以调用,第一种方法将继续有效,而第二种方法将永远不会返回。

【讨论】:

  • 您能否详细说明先决条件的变化,因为您提到的问题可以通过将CountDownLatch 实例化为final CountDownLatch countDownLatch = new CountDownLatch(validationSvcs.size()); 并将方法包含在If 子句中来解决
  • 是的,你可以这样做。这仍然是可能容易出错的外部协调,而 CompletableFuture 的固有机制已经为您提供了所需的一切。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2012-10-10
相关资源
最近更新 更多