Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asynchronous non-blocking task with CompletableFutures

I have the need to create an asynchronous, non-blocking task in Java 8, I would like to use CompletableFutures but I'm not sure if it fulfils my needs.

To simplify the case, let's say we have an API that retrieve some data for the user but at the same time want to start a separate task to do some operations. I don't need and don't want to wait for this separate task to finish, I want to send the response right away to the user. An example in mock code:

public Response doSomething(params) {
  Object data = retrieveSomeData(params);

  // I don't want to wait for this to finish, I don't care if it succeeds or not
  doSomethingNoWait(data);

  return new Response(data);
}

I was looking at CompletableFutures, something like this:

CompletableFuture.supplyAsync(this::doSomethingNoWait)  
             .thenApply(this::logSomeMessage); 

What I would like to know is if that is the correct approach? Would the response be returned to the user before doSomethingNoWait finish what it has to do?

Thanks!

like image 299
malavock Avatar asked Aug 17 '18 12:08

malavock


People also ask

How CompletableFuture is non-blocking?

CompletableFuture is used for asynchronous programming in Java. Asynchronous programming is a means of writing non-blocking code by running a task on a separate thread than the main application thread and notifying the main thread about its progress, completion or failure.

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.

Is CompletableFuture thenAccept blocking?

Unlike stated in some blogs(e.g. I can't emphasize this enough: thenAccept()/thenRun() methods do not block) CompletableFuture. thenAccept can indeed block. Consider the following code, uncommenting the pause method call will cause thenAccept to block: CompletableFuture<String> future = CompletableFuture.

What does CompletableFuture run async do?

You can use the CompletableFuture interface for asynchronous programming. In other words, this interface runs a task in a non-blocking thread. After execution, it notifies the caller thread about the task progress, completion, or any failure.


1 Answers

Great question. Yes a CompleteableFuture is perfect for your needs! Lets investigate further the functionality of the class.

A CompleteableFuture is a wrapper for the Future class and allows for executing in parallel. Lets take a look at an example from this article.

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        throw new IllegalStateException(e);
    }
    return "Result of the asynchronous computation";
});

In the above example, the program will start the CompletableFuture asynchronously and will have the new thread sleep in the background. If we add .thenApply() seen below:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        throw new IllegalStateException(e);
    }
    return "Result of the asynchronous computation";
}).thenApply(result -> {
   System.out.println(result);
   return "Result of the then apply";
});

The application will execute just as we discussed before, but once it completes (non-exceptionally) the current thread running the supplyAsync will execute the print statement.

Note, if a synchronous transformation is added to a future after it has finished execution, the calling thread will perform the transformation. As we see below:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        throw new IllegalStateException(e);
    }
    return "Result of the asynchronous computation";
});
// Long calculations that allows the future above to finish
future.thenApply(result -> {
   System.out.println(result);
   return "Result of the then apply";
});

the thenApply will run on the thread that runs future.thenApply(...), not the thread spawned to run the supplyAsync in the background.

like image 117
Impurity Avatar answered Sep 23 '22 20:09

Impurity