Hello! ExecutorService.invokeAll is a powerful method when you have a collection of tasks and need to wait until every single one of them finishes before moving forward.
Here’s a breakdown of how it works and how to use it effectively.
What does invokeAll do?
- Executes a collection of tasks: It takes a
CollectionofCallable<T>objects. - Blocks until completion: Unlike
submit(), which returns immediately,invokeAllis blocking. It will not return until all tasks in the collection have completed (either normally or by throwing an exception). - Returns a list of Futures: It returns a
List<Future<T>>that holds the results (or exceptions) of the tasks, in the same order they were provided in the input collection.
Basic Usage Pattern
Here is a clean example of how to implement it:
package org.kodejava.util.concurrent;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
public class InvokeAllDemo {
public static void main(String[] args) {
// 1. Create your ExecutorService
try (ExecutorService executor = Executors.newFixedThreadPool(3)) {
// 2. Define your tasks (Callable returns a value)
List<Callable<String>> tasks = Arrays.asList(
() -> { Thread.sleep(500); return "Result A"; },
() -> { Thread.sleep(1000); return "Result B"; },
() -> { Thread.sleep(200); return "Result C"; }
);
try {
// 3. Invoke all tasks. Execution stops here until all are done.
System.out.println("Executing tasks...");
List<Future<String>> futures = executor.invokeAll(tasks);
// 4. Process the results
for (Future<String> future : futures) {
// Future.get() will not block here because invokeAll already waited
System.out.println("Task output: " + future.get());
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
} // Executor closes automatically with try-with-resources (Java 19+)
}
}
Important Considerations
- Order Preservation: The returned
List<Future>maintains the same order as the input task list.futures.get(0)will always correspond totasks.get(0). - Timeouts: There is an overloaded version:
invokeAll(tasks, timeout, unit). If the timeout expires, tasks that haven’t finished are canceled, and the method returns the list of futures (some will be marked as canceled). - Exceptions: If a task throws an exception,
invokeAlldoesn’t fail. Instead, that specificFuture.get()will throw anExecutionException. - Blocking Behavior: Since
invokeAllblocks the calling thread, avoid calling it on a thread that needs to stay responsive (like a UI thread or a primary event loop) without careful planning.
When to use it vs invokeAny?
- Use
invokeAllwhen you need the results of everything you started. - Use
invokeAnywhen you have multiple ways to get a result, and you only care about the first one that finishes successfully (it cancels the rest).
Happy coding! If you’re working within a Spring environment, you might also want to look into @Async for higher-level abstraction, but for raw concurrency control, invokeAll is a classic choice.
