Lesson 8 / 38
Executors & Futures
Decouple task submission from thread management with ExecutorService, run Callables, collect results from Future, and always shut the pool down.
Submit work to a pool
An ExecutorService decouples task submission from thread management. submit(Callable<T>) returns a Future<T>; future.get() blocks for the result. Always shutdown() the pool.
try (var pool = Executors.newFixedThreadPool(4)) {
List<Future<Integer>> fs = pool.invokeAll(tasks);
for (Future<Integer> f : fs) total += f.get();
} // close() shuts down and waits (Java 19+)Pick the right pool
newFixedThreadPool(n) for bounded CPU-bound work, newCachedThreadPool() for many short-lived bursty tasks, and Java 21's Executors.newVirtualThreadPerTaskExecutor() for thousands of blocking IO tasks — one virtual thread per task, no pool sizing needed.
try (var pool = Executors.newVirtualThreadPerTaskExecutor()) {
urls.forEach(url -> pool.submit(() -> fetch(url)));
}