How do I submit multiple tasks and get results using invokeAll?

To submit multiple tasks and get results using invokeAll in Java, you can make use of the ExecutorService. The invokeAll method submits a collection of Callable tasks to the executor and waits for all of them to complete. Once completed, it returns a list of Future objects, each representing the result of a corresponding task.

Here’s how it works:

  1. Create a collection of Callable tasks: These tasks are units of work that the executor will execute in parallel.
  2. Submit the tasks using invokeAll: The invokeAll method blocks until all tasks are complete or timed out.
  3. Retrieve the results from the Future objects: Each Future object allows you to get the result of its corresponding task or check for exceptions.

Example Code

package org.kodejava.util.concurrent;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class InvokeAllExample {
   public static void main(String[] args) {
      // Create a fixed thread pool
      ExecutorService executorService = Executors.newFixedThreadPool(3);

      // Create a collection of Callable tasks
      List<Callable<String>> tasks = new ArrayList<>();
      tasks.add(() -> {
         // Simulate doing some work
         Thread.sleep(1000);
         return "Task 1 completed";
      });
      tasks.add(() -> {
         Thread.sleep(2000);
         return "Task 2 completed";
      });
      tasks.add(() -> {
         Thread.sleep(1500);
         return "Task 3 completed";
      });

      try {
         // Submit the tasks and wait for all of them to complete
         List<Future<String>> results = executorService.invokeAll(tasks);

         // Iterate through the futures to retrieve the results
         for (Future<String> future : results) {
            try {
               // Get the result of each task
               System.out.println(future.get());
            } catch (ExecutionException e) {
               System.err.println("Task encountered an issue: " + e.getMessage());
            }
         }
      } catch (InterruptedException e) {
         System.err.println("Task execution was interrupted: " + e.getMessage());
      } finally {
         // Shutdown the executor service
         executorService.shutdown();
      }
   }
}

Explanation:

  1. ExecutorService:
    • A thread pool is created (Executors.newFixedThreadPool(3)), which allows up to 3 threads to run simultaneously.
  2. List of Callable tasks:
    • Each task implements the Callable interface and returns a result. For example, the tasks simulate work by Thread.sleep() and return a string.
  3. invokeAll Method:
    • executorService.invokeAll(tasks) submits all tasks at once and blocks until all tasks are complete.
  4. Retrieving Results:
    • The method returns a list of Future objects, where future.get() is used to retrieve the result of each task.
  5. Exceptions:
    • Handle InterruptedException (if the current thread is interrupted) and ExecutionException (if a task fails with an exception).
  6. Shutdown the Executor:
    • Always call shutdown() to properly terminate the executor service and release resources.

Output:

Task 1 completed
Task 3 completed
Task 2 completed

(Note: The order may vary since the tasks run concurrently.)

Keynotes:

  • Use ExecutorService to manage thread pools efficiently.
  • The invokeAll method blocks until all tasks are complete.
  • Handle exceptions like InterruptedException and ExecutionException.
  • Always shut down the executor service to free resources.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.