ExecutorService / Executors.newFixedThreadPool()
A mechanism for efficiently executing multiple tasks in parallel using a thread pool (available since Java 5). Because it automatically manages thread creation, reuse, and termination, it is safer and more performant than using Thread directly.
Syntax
import java.util.concurrent.*; // Creates a fixed-size thread pool. ExecutorService exec = Executors.newFixedThreadPool(numThreads); // Creates an Executor backed by a single thread. ExecutorService exec = Executors.newSingleThreadExecutor(); // Creates a pool that grows and shrinks as needed. ExecutorService exec = Executors.newCachedThreadPool(); // Submits a Runnable task (no return value). exec.execute(Runnable task); // Submits a Callable task and returns a Future (with return value). Future<T> future = exec.submit(Callable<T> task); T result = future.get(); // Blocks until the result is available. // Shuts down the ExecutorService (required). exec.shutdown(); exec.shutdownNow(); // Forcibly stops all running tasks.
Main Methods
| Method | Description |
|---|---|
| Executors.newFixedThreadPool(n) | Creates a fixed-size pool with n threads. |
| Executors.newSingleThreadExecutor() | Queues and executes tasks sequentially on a single thread. |
| Executors.newCachedThreadPool() | Creates and reuses threads as needed. Well-suited for short-lived tasks. |
| execute(Runnable) | Executes a task asynchronously. Returns no value. |
| submit(Callable<T>) | Executes a task asynchronously and returns the result as a Future<T>. |
| future.get() | Blocks and waits until the task's result is available. |
| shutdown() | Stops accepting new tasks and waits for existing tasks to complete before terminating. |
| shutdownNow() | Interrupts running tasks and shuts down immediately. |
| awaitTermination(timeout, unit) | Waits for termination up to the specified timeout. |
Sample Code
import java.util.concurrent.*;
// Runs 5 tasks concurrently using a pool of 3 threads.
ExecutorService exec = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 5; i++) {
final int taskId = i;
exec.execute(() -> {
System.out.println("Task " + taskId + " running on: " + Thread.currentThread().getName());
try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
System.out.println("Task " + taskId + " completed.");
});
}
// Stops accepting new tasks and waits for remaining tasks to finish.
exec.shutdown();
// Uses submit() to run tasks that return a value.
ExecutorService exec2 = Executors.newFixedThreadPool(2);
Future<Integer> future1 = exec2.submit(() -> { Thread.sleep(200); return 10 + 20; });
Future<Integer> future2 = exec2.submit(() -> { Thread.sleep(100); return 30 + 40; });
try {
System.out.println("Result 1: " + future1.get()); // Prints "Result 1: 30".
System.out.println("Result 2: " + future2.get()); // Prints "Result 2: 70".
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
exec2.shutdown();
}
Notes
Using a thread pool reduces the overhead of creating threads and improves application throughput. For Executors.newFixedThreadPool(), it is common to set the thread count to match the number of CPU cores. For I/O-heavy workloads, using more threads than CPU cores can be more effective.
If you do not call shutdown(), the program may hang and never terminate. Always call it using a try-finally block. For more advanced async processing, use CompletableFuture, which lets you compose and chain multiple asynchronous tasks.
For the basics of threads, see new Thread() / thread.start() / Runnable.
If you find any errors or copyright issues, please contact us.