use of CompletableFuture.supplyAsync and CompletableFuture.completedFuture within @Async annotation in spring boot
Asked Answered
E

1

5

I have the following methods:

@EnableAsync
@Service
Class MyService{ 

private String processRequest() {
        log.info("Start processing request");

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        log.info("Completed processing request");
        return RESULT;
    }    

@Async
public CompletableFuture<String> getSupplyAsyncResult(){
    CompletableFuture<String> future
            = CompletableFuture.supplyAsync(this::processRequest);
    return future;
}

@Async
public CompletableFuture<String> getCompletedFutureResult(){
    CompletableFuture<String> future
            = CompletableFuture.supplyAsync(this::processRequest);
    return future;
}

and the following endpoints in controller:

   @RequestMapping(path = "/asyncSupplyAsync", method = RequestMethod.GET)
    public CompletableFuture<String> getValueAsyncUsingCompletableFuture() {
        log.info("Request received");
        CompletableFuture<String> completableFuture
                = myService.getSupplyAsyncResult();
        log.info("Servlet thread released");
        return completableFuture;
    }

and

   @RequestMapping(path = "/asyncCompletable", method = RequestMethod.GET)
    public CompletableFuture<String> getValueAsyncUsingCompletableFuture() {
        log.info("Request received");
        CompletableFuture<String> completableFuture
                = myService.getCompletedFutureResult();
        log.info("Servlet thread released");
        return completableFuture;
    }

Why would anyone use completableFuture.supplyAsync within @Async method in Spring endpoint? I assume using completableFuture.completedFuture is more appropriate, please share your views.

Excogitate answered 6/11, 2020 at 17:17 Comment(0)
P
7

They serve entirely different purposes to begin with. Before you think about how much it takes one or the other to process, you might want to understand how they work, first (so little calls are no indication of slow/fast anyway; these numbers mean nothing in this context).

Here is the same example you have:

public class SO64718973 {

    public static void main(String[] args) {
        System.out.println("dispatching to CF...");
        //CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> processRequest());
        CompletableFuture<String> future = CompletableFuture.completedFuture(processRequest());
        System.out.println("done dispatching to CF...");
        future.join();
    }

    private static String processRequest() {
        System.out.println("Start processing request");

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println("Completed processing request");
        return "RESULT";
    }

}

You can run this and then change the implementation (by uncommenting CompletableFuture.supplyAsync) and see where those System.out.println occur. You will notice that completedFuture will block main thread until it is executed, while supplyAsync will run in a different thread. So it's not like one is wrong and one is not, it depends on your use-case.

In general, it is not a great idea to use CompletableFuture.supplyAsync without configuring a pool for it; otherwise it will consume threads from ForkJoinPool.

Paint answered 13/11, 2020 at 22:5 Comment(3)
thanks for clarification, but if completedFuture() is executed by main thread (and not another thread in ForkJoinPool), then whats the need to basically use it since we can normally call our methods without even using completedFuture?Excogitate
@MortezaN in this case it is completed by main thread . There is nothing stopping you or anyone else from sharing this CompletableFuture so that some other thread can complete it.Paint
in the case of async spring, we have configured the executor. So does it mean that we should prefer supplyAsync in order to wrap blocking operation?Joust

© 2022 - 2024 — McMap. All rights reserved.