Morteza Naeimabadi
Morteza Naeimabadi

Reputation: 1020

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

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.

Upvotes: 5

Views: 5890

Answers (1)

Eugene
Eugene

Reputation: 120858

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.

Upvotes: 7

Related Questions