Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CompletableFuture, supplyAsync() and thenApply()

Need to confirm something. The following code:

CompletableFuture     .supplyAsync(() -> {return doSomethingAndReturnA();})     .thenApply(a -> convertToB(a)); 

would be the same as:

CompletableFuture     .supplyAsync(() -> {         A a = doSomethingAndReturnA();         convertToB(a);  }); 

Right?

Furthermore, another two questions following as for "is there any reason why we would use thenApply?"

1) having big code for conversion?

or

2) need to reuse the lambda block in other places?

like image 289
igr Avatar asked Dec 31 '14 16:12

igr


People also ask

What is difference between supplyAsync and runAsync?

The difference between runAsync() and supplyAsync() is that the former returns a Void while supplyAsync() returns a value obtained by the Supplier. Both methods also support a second input argument — a custom Executor to submit tasks to.

What is difference between thenApply and thenCompose?

thenApply is the map and thenCompose is the flatMap of CompletableFuture . You use thenCompose to avoid having CompletableFuture<CompletableFuture<..>> .

What does CompletableFuture supplyAsync do?

CompletableFuture executes these tasks in a thread obtained from the global ForkJoinPool. commonPool(). But hey, you can also create a Thread Pool and pass it to runAsync() and supplyAsync() methods to let them execute their tasks in a thread obtained from your thread pool.

What is thenApply in Java?

thenApply() is an instance method of the CompletableFuture class that processes a stage's result. It accepts a Function functional interface that accepts an argument and returns a result. This method also chains multiple stages of computation together.


2 Answers

It is not the same thing. In the second example where thenApply is not used it is certain that the call to convertToB is executed in the same thread as the method doSomethingAndReturnA.

But, in the first example when the thenApply method is used other things can happen.

First of all, if the CompletableFuture that executes the doSomethingAndReturnA has completed, the invocation of the thenApply will happen in the caller thread. If the CompletableFutures hasn't been completed the Function passed to thenApply will be invoked in the same thread as doSomethingAndReturnA.

Confusing? Well this article might be helpful (thanks @SotiriosDelimanolis for the link).

I have provided a short example that illustrates how thenApply works.

public class CompletableTest {     public static void main(String... args) throws ExecutionException, InterruptedException {         final CompletableFuture<Integer> future = CompletableFuture                 .supplyAsync(() -> doSomethingAndReturnA())                 .thenApply(a -> convertToB(a));          future.get();     }      private static int convertToB(final String a) {         System.out.println("convertToB: " + Thread.currentThread().getName());         return Integer.parseInt(a);     }      private static String doSomethingAndReturnA() {         System.out.println("doSomethingAndReturnA: " + Thread.currentThread().getName());         try {             Thread.sleep(1000);         } catch (InterruptedException e) {             e.printStackTrace();         }          return "1";     } } 

And the output is:

doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1 convertToB: ForkJoinPool.commonPool-worker-1 

So, when the first operation is slow (i.e. the CompletableFuture is not yet completed) both calls occur in the same thread. But if the we were to remove the Thread.sleep-call from the doSomethingAndReturnA the output (may) be like this:

doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1 convertToB: main 

Note that convertToB call is in the main thread.

like image 78
wassgren Avatar answered Sep 18 '22 05:09

wassgren


thenApply() is a callback function, which will be executed when supplyAsync() return a value.

In code snippet 2, the thread which invoked doSomethingAndReturnA() waits for the function to get executed and return the data.

But in some exceptional cases (like making Webservice call and waiting for response), the thread has to wait for long time to get the response, which badly consumes lot of system computation resources (just waiting for response).

To avoid that, CompletableFuture comes with callback feature, where once the doSomethingAndReturnA() is invoked, a separate thread will take care of executing doSomethingAndReturnA() and the main caller thread will continue to do other operations without waiting for the response to return.

Once the response of doSomethingAndReturnA is available, the call back method will be invoked (i.e., thenApply())

like image 44
user3016425 Avatar answered Sep 19 '22 05:09

user3016425