Core Module
12 min forge
Java Thread Pools and Executors
Managing threads efficiently using the ExecutorService. Avoiding the "One Thread per Task" anti-pattern.
Java Thread Pools and Executors
π‘οΈ What are Executors?
The java.util.concurrent.ExecutorService is a high-level API for managing a pool of worker threads. Instead of manually creating new Thread() for every task (which is expensive and risks resource exhaustion), you submit tasks to a pool that manages thread reuse and scheduling.
β° When to Use
- High Concurrency: When your application needs to handle many short-lived asynchronous tasks.
- Resource Management: To limit the maximum number of concurrent threads to prevent memory crashes.
- Async Execution: Running tasks in the background without blocking the main execution thread.
π Complexity & Performance
- Initialization: Creating a thread pool has an $O(k)$ overhead where $k$ is the pool size.
- Task Submission: Submitting a task is usually $O(1)$, though it may involve waiting on a blocking queue if the pool is full.
- Context Switching: Thread pools reduce context switching overhead by reuse, but too many threads can still degrade performance due to CPU contention.
π» Code Example: Fixed Thread Pool
java Standardimport java.util.concurrent.*; public class ExecutorDemo { public static void main(String[] args) { // 1. Create a pool of 4 worker threads ExecutorService executor = Executors.newFixedThreadPool(4); for (int i = 0; i < 10; i++) { final int taskId = i; // 2. Submit task executor.submit(() -> { System.out.println("Processing task " + taskId + " on " + Thread.currentThread().getName()); try { Thread.sleep(500); } catch (InterruptedException e) {} }); } // 3. Graceful Shutdown executor.shutdown(); try { if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); } } catch (InterruptedException e) { executor.shutdownNow(); } } }
β οΈ Interview Pitfalls
- Unbounded Queues:
Executors.newFixedThreadPool()uses aLinkedBlockingQueuewith no capacity limit. If tasks arrive faster than they are processed, the application will run out of memory (OutOfMemoryError). - Infinite Waiting: Always call
shutdown()andawaitTermination(). A thread pool that isn't shut down will prevent the JVM from exiting. - Thread Visibility: Remember that variables shared between the main thread and executors must be
volatileor accessed via thread-safe classes (likeAtomicInteger). - Exception Masking: In a thread pool, if a task throws an unchecked exception, it might be "swallowed" unless you are looking at the
Futureobject returned bysubmit().