Reputation: 1020
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
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