Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 - Call methods async in parallel and combine their results

I am new to the Java 8 concurrency features such as CompletableFuture and I hope you can help to get started with the following use case.

There is a service called TimeConsumingServices that provides time consuming operations which I'd like to run in parallel since all of them are independent.

interface TimeConsumingService {

  default String hello(String name) {
    System.out.println(System.currentTimeMillis() + " > hello " + name);
    return "Hello " + name;
  }
  default String planet(String name) {
    System.out.println(System.currentTimeMillis() + " > planet " + name);
    return "Planet: " + name;
  }
  default String echo(String name) {
    System.out.println(System.currentTimeMillis() + " > echo " + name);
    return name;
  }

  default byte[] convert(String hello, String planet, String echo) {
    StringBuilder sb = new StringBuilder();
    sb.append(hello);
    sb.append(planet);
    sb.append(echo);
    return sb.toString().getBytes();
  }
}

So far I implemented the following example and I have managed to call all three service methods in parallel.

public class Runner implements TimeConsumingService {

  public static void main(String[] args) {
    new Runner().doStuffAsync();
  }

  public void doStuffAsync() {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> this.hello("Friend"));
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> this.planet("Earth"));
    CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> this.echo("Where is my echo?"));

    CompletableFuture.allOf(future1, future2, future3).join();
  }
}

Is there a way to collect the return values of each service call and invoke the method byte[]‘ convert(String, String, String)?

like image 385
saw303 Avatar asked Feb 28 '17 09:02

saw303


People also ask

Is parallel stream async?

An operation on a ParallelStream is still blocking and will wait for all the threads it spawned to finish. These threads are executed asynchronously (they don't wait for a previous one to finish), but that doesn't mean your whole code starts behaving asynchronously !

Can we call async method from same class?

Async with @Async Users can use it only on public methods and can't call the methods from the same class where they are defined. Any code that is inside a method annotated with Async will be executed in a different thread and can be void or can return a CompletableFuture.

Is forEach asynchronous Java?

forEach Asynchronous? It is not asynchronous. It is blocking. Those who first learned a language like Java, C, or Python before they try JS will get confused when they try to put an arbitrary delay or an API call in their loop body.


2 Answers

To combine the result after you have returned them all you can do something like this

CompletableFuture<byte[]> byteFuture = CompletableFuture.allOf(cf1, cf2, cf3)
                     .thenApplyAsync(aVoid -> convert(cf1.join(), cf2.join(), cf3.join()));
byte[] bytes = byteFuture.join();

This will run all of your futures, wait for them all to complete, then as soon as they are all finished will call your convert method you mention.

like image 76
Ash Avatar answered Sep 18 '22 14:09

Ash


After join you can simply get() values from future1 like:

String s1 = future1.get()

and so on

like image 20
user2377971 Avatar answered Sep 17 '22 14:09

user2377971