Calling a method in parallel which returns the future

Posted on

Problem

I have an async method which calls my Task class while my Task class does all the work:

    private ExecutorService executor = Executors.newFixedThreadPool(10);

    @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;
    }

Here 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>();

    // here keys max size will be three
    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(300, TimeUnit.MILLISECONDS));
        } catch (Exception e) {
            // do something
        }
    }
    return responseList;
}

My intention is to call executeAsync method in parallel and return back responseList object. I mean I want to execute call method of my Task class in parallel for each of the key object so if I have three key object in keys list, then I want to execute call method for each key in parallel and then make a List<DataResponse> object and return it.

Since I don’t want to wait 300 Milliseconds for each key future and then call next key future and then next call third key future. In this way it will wait 300 + 300 + 300 for each of the key. I want to execute call method in parallel in same 300 milliseconds for all three keys.

Does my above code looks right, and are there any better ways of doing this problem? I am still on Java 7.

Solution

An executor service will be able to do a invokeAll with a timeout and return a set of futures holding all the values or return when the timeout expires.

This means that your executeAsync should take a set of keys and build all the tasks from those at once and then submit the tasks as a batch:

@Override
public List<Future<DataResponse>> executeAsync(Collection<DataKey> keys,  long timeout, TimeUnit unit) {
    List<Task> tasks = new ArrayList<>(keys.size());
    for(DataKey key : keys){
        tasks.add(new Task(key, restTemplate));
    }

    return executor.invokeAll(tasks, timeout, unit);
}


@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>();

    List<Future> futures = executeAsync(keys, 300, TimeUnit.MILLISECONDS);


    for (Future<DataResponse> future : futures) {
        try {
            if(future.isDone())
                responseList.add(future.get());
            //otherwise future didn't complete in the 300 milliseconds
        } catch (Exception e) {
            // do something
        }
    }
    return responseList;
}

Leave a Reply

Your email address will not be published. Required fields are marked *