为什么使用completableFuture如果任务是从属的

问题描述 投票:0回答:1

我在需要处理订单处理的应用程序中非常高效地使用ExecutorServices,现在,订单生命周期具有多个阶段,需要按顺序完成。而2个订单应相互独立处理。

Sudo代码如下:

ExecutorService service = Executors.newFixedThreadPool(100);
    List<Future<Boolean>> orderStatus = new ArrayList<>(); 
    for (int i = 0; i < 100 ; i++) {
        Future<Boolean> status = service.submit(() -> {
            ProcessOrder();
        });
        orderStatus.add(status);
    }

public Boolean ProcessOrder(){
   Order order = PollOrder();
   order =  EnrichOrder(order);
   order =  Payment(order);
   order =  confirmOrder(order);
   return true;
}

另一方面,如果我使用的是CompleteableFuture,我看到的唯一好处就是使用了公共的forkjoin池,在该池中代码看起来简单易读,但是由于任务以相同的顺序相互依赖,所以实际处理是什么无论如何,当get()阻塞时使用CompleteableFuture的好处。

for (int i = 0; i < 100 ; i++) {
    CompletableFuture<Order> orderStatus= CompletableFuture.supplyAsync(()->pollOrder())
            .thenApply(order -> enrichOrder(order))
            .thenApply(order -> payment(order))
            .thenApply(order -> confirmOrder(order)); 
}
java multithreading concurrency completable-future
1个回答
0
投票

我认为一个优势是更好地利用线程池。 ExecutorService代码示例对每个操作使用相同的池。这些操作可能是IO密集型或计算密集型。在不同的池上运行这些操作将更好地利用系统资源。(*)使用CompletableFuture的异步方法在不同的池上运行任务非常容易。

CompletableFuture.supplyAsync(()->comp1()) // start in common-pool
            .thenApplyAsync(order -> io1(order),ioPool) // lets say this is IO operation 
            .thenApplyAsync(order -> comp2(order)) // switch back to common-pool
            .thenApplyAsync(order -> io2(order),ioPool); // another io

在此示例中,当comp1任务完成时,io1任务将在IO线程池中执行,并且公共池线程可以在此期间服务其他任务。在io1任务结束时,comp2任务将被提交到公共池。

您可以在不使用CompletableFuture的情况下实现相同的功能,但是代码将更加复杂。 (例如,将comp2任务作为参数传递给io1方法,最后将其从io1方法提交到公共池。)

同样在编写异步代码时,我认为completableFuture管道应该以另一个异步调用而不是get方法来完成。

(*)假设这是在8核计算机上工作的代码,向100个线程的池提交100个计算任务的性能不会比一次运行8个线程的性能更好。

© www.soinside.com 2019 - 2024. All rights reserved.