john
john

Reputation: 11669

How to call a method in parallel which returns the future?

I have an async method as shown below which calls my Task class and my Task class does all the work.

    @Override
    public Future<DataResponse> executeAsync(DataKey key) {
        Future<DataResponse> future = null;

        try {
            Task task = new Task(key, restTemplate);
            future = executor.submit(task); 
        } catch (Exception ex) {
            // logging exception here
        }

        return future;
    }

Below is my Task class which does all the work:

public class Task implements Callable<DataResponse> {

    private DataKey key;
    private RestTemplate restTemplate;

    public Task(DataKey key, RestTemplate restTemplate) {
        this.key = key;
        this.restTemplate = restTemplate;
    }

    @Override
    public DataResponse call() throws Exception {
        // some code here
    }
}

Now I need to call executeAsync method in parallel and then make a List<DataResponse> object and return it.

@Override
public List<DataResponse> executeSync(DataKey key) {
    List<DataResponse> responseList = new ArrayList<DataResponse>();

    // make a List of DataKey using single key passed to this method.       
    List<DataKey> keys = new ArrayList<DataKey>();

    for(DataKey key : keys) {


    }
}

How can I call executeAsync method in parallel and return back responseList? In my keys list maximum I will have six DataKey object.

Upvotes: 0

Views: 2082

Answers (3)

Zbynek Vyskovsky - kvr000
Zbynek Vyskovsky - kvr000

Reputation: 18825

There is no reason to execute it in parallel as internally it already runs in parallel. The only thing you need is calling the async method for each of the items and store resulting Futures in the list. After this loop is over you need to go through the list of those Futures, and calling get()on each of them gives the result. These result list you'll return as the return value.

Upvotes: 0

akki
akki

Reputation: 451

You can call Executor service invokeAll method and submit List of Task to it. Executor Service will execute the tasks in parallel.

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#invokeAll(java.util.Collection)

This would be same as: 1. invoking executeAsync in parallel from the for loop in executeSync method. 2. invoking executeAsync method sequentially from the for loop in executeSync method.

Upvotes: 0

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279940

If you're expecting to return a List<DataResponse> containing the DataResponse objects returned by Task#call, you can't do this asynchronously. You'll need to block inside executeSync to wait for the result of all futures.

List<Future> futures = new ArrayList<>(keys.size());
for(DataKey key : keys) {
    Future<DataResponse> future = executeAsync(key);
    futures.add(future);
}

for (Future<DataResponse> future : futures) {
    try {
        responseList.add(future.get());
    } catch (Exception e) {
        // do something else.
    }
    return responseList
}

A more appropriate solution with Future is to use a CompletionService, as detailed here.

In Java 8, you should be using CompletableFuture (or Guava's ListenableFuture) for asynchronous tasks. You can still do what I did above, or you can change your code to take full advantage of continuation tasks.

Upvotes: 1

Related Questions