Java ExecutorService invokeAll()

Learn to run multiple Callable tasks with ExecutorService.invokeAll() API and processing all the results returned from tasks in form of Future class instances in this ExecutorService Callable example.

1. ExecutorService invokeAll() API

The invokeAll() method executes the given list of Callable tasks, returning a list of Future objects holding their status and results when all are complete.

It is an overloaded method and is in two forms. The second method takes extra parameters denoting the timeout. The TimeUnit class is an enumeration with the following constants: DAYS, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, and SECONDS.

/**
* @param  - tasks - the collection of tasks
* @return - a list of Futures representing the tasks, in the same
*           sequential order as produced by the iterator for the
*           given task list.
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
 
/**
* @param - tasks - the collection of tasks
* @param - timeout - the maximum time to wait
* @param - unit - the time unit of the timeout argument
* @return - a list of Futures representing the tasks, in the same
*           sequential order as produced by the iterator for the
*           given task list.
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)

An important point to note is that the first object in the list of Future objects will be the object that controls the first task in the list of Callable objects, the second object the second task, and so on.

2. ExecutorService invokeAll() Example

In this example, we are creating a demo task that does nothing but prints some statements. This is not to introduce any complexity and focus on the core concept.

class Task implements Callable<Result> 
{
  private final String name;
 
  public Task(String name) {
    this.name = name;
  }
 
  @Override
  public Result call() throws Exception 
  {
    System.out.printf("%s: Staring\n", this.name);
 
    try {
      long duration = (long) (Math.random() * 10);
      System.out.printf("%s: Waiting %d seconds for results.\n", this.name, duration);
      TimeUnit.SECONDS.sleep(duration);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
 
    return new Result(this.name, LocalDateTime.now().toString());
  }
}

Similarly, we collect the result after the execution of the task in the Result class which stores the name of the task and the timestamp when the task is completed.

class Result 
{
  private String name;
  private String timestamp;
 
  public Result(String name, String timestamp) {
    super();
    this.name = name;
    this.timestamp = timestamp;
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public String getTimestamp() {
    return timestamp;
  }
 
  public void setTimestamp(String timestamp) {
    this.timestamp = timestamp;
  }
 
  @Override
  public String toString() {
    return "Result [name=" + name + ", value=" + timestamp + "]";
  }
}

In this example, we have submitted 5 tasks which are submitted to the executor service using invokeAll() method. All tasks are executed at different time duration as only two threads are in the thread pool.

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
 
public class Main 
{
  public static void main(String[] args) throws InterruptedException 
  {
    ExecutorService executor = (ExecutorService) Executors.newFixedThreadPool(2);
 
    List<Task> taskList = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
      Task task = new Task("Task-" + i);
      taskList.add(task);
    }
     
    //Execute all tasks and get reference to Future objects
    List<Future<Result>> resultList = null;
 
    try {
      resultList = executor.invokeAll(taskList);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
 
    executor.shutdown();
 
    System.out.println("\n========Printing the results======");
     
    for (int i = 0; i < resultList.size(); i++) {
      Future<Result> future = resultList.get(i);
      try {
        Result result = future.get();
        System.out.println(result.getName() + ": " + result.getTimestamp());
      } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
      }
    }
  }
}

Program output.

Task-0: Staring
Task-0: Waiting 7 seconds for results.
Task-1: Staring
Task-1: Waiting 1 seconds for results.
Task-2: Staring
Task-2: Waiting 2 seconds for results.
Task-3: Staring
Task-3: Waiting 3 seconds for results.
Task-4: Staring
Task-4: Waiting 4 seconds for results.

========Printing the results======

Task-0: 2019-05-23T12:56:33.692
Task-1: 2019-05-23T12:56:27.885
Task-2: 2019-05-23T12:56:29.887
Task-3: 2019-05-23T12:56:32.889
Task-4: 2019-05-23T12:56:36.890

The main thing to notice is that even if a few tasks are completed, the program does not start printing the results. We get the result only after all the tasks are completed.

Drop me your questions related to Java ExecutorService Callable Example in the comments section.

Happy Learning !!

Leave a Reply

0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial