Syntax
ExecutorService executor = Executors.newFixedThreadPool(n);Examples
Basic ExecutorService Usage
Submitting tasks to a thread pool instead of manually managing Thread objects.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 5; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println("Running task " + taskId + " on " + Thread.currentThread().getName());
});
}
executor.shutdown(); // stop accepting new tasks, let submitted ones finishGetting Results with Future
submit() returns a Future, letting you retrieve a task's result once it completes.
import java.util.concurrent.*;
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Integer> future = executor.submit(() -> {
Thread.sleep(100);
return 42;
});
try {
Integer result = future.get(); // blocks until the task finishes
System.out.println("Result: " + result);
} catch (InterruptedException | ExecutionException e) {
System.out.println("Task failed: " + e.getMessage());
}
executor.shutdown();Different Executor Types
Executors provides several pool configurations for different needs.
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
ExecutorService fixedPool = Executors.newFixedThreadPool(4); // exactly 4 threads
ExecutorService cachedPool = Executors.newCachedThreadPool(); // grows/shrinks as needed
ExecutorService singleThread = Executors.newSingleThreadExecutor(); // one thread, tasks run in order
singleThread.submit(() -> System.out.println("Task A"));
singleThread.submit(() -> System.out.println("Task B")); // guaranteed to run after A
fixedPool.shutdown();
cachedPool.shutdown();
singleThread.shutdown();Best practices
- Always call shutdown() (or shutdownNow() for immediate termination) when done with an ExecutorService - forgetting to do so leaves threads running indefinitely
- Use newFixedThreadPool() for a predictable, bounded number of concurrent tasks, protecting your system from unbounded thread creation
- Handle both InterruptedException and ExecutionException when calling future.get(), since either can occur if the task fails or is interrupted
- Prefer ExecutorService over manually creating raw Thread objects for any real application - it is more efficient and easier to manage correctly
Runtime & versions
Java Virtual Machine. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
Java Language Specification