Multithreading
ExecutorService
Understand the Java Executor framework, standard thread pool types, and configurations.
Interview: Heavily tested on ThreadPoolExecutor configuration parameters (corePoolSize, maxPoolSize, keepAliveTime, workQueue, and rejection policies).
The ExecutorService interface represents the standard Java framework for executing asynchronous tasks. Decoupling task submission from thread management allows configuring complex pooling strategies and task queues.
Core Idea
ExecutorService provides thread execution pools. Configure core/max sizes, queues, and rejection policies.
Why It Matters
Tuning pool size and queues prevents application resource exhaustion and thread starvation.
Interview Lens
Expect deep dives into thread pool growth mechanics (how corePoolSize, maxPoolSize, and queueCapacity interact).
ThreadPoolExecutor Parameters
When creating a custom ThreadPoolExecutor, you configure:
corePoolSize: The number of threads to keep in the pool, even if they are idle.maximumPoolSize: The maximum number of threads allowed in the pool.workQueue: The blocking queue used to hold tasks before execution.handler: The Rejection Policy executed when the queue is full and threads are saturated (e.g.AbortPolicy,CallerRunsPolicy,DiscardPolicy,DiscardOldestPolicy).
Growth Mechanics (Crucial Interview Detail)
When a task is submitted:
1. If active threads < corePoolSize, a new thread is created.
2. If active threads >= corePoolSize, the task is added to the workQueue.
3. If the queue is full and active threads < maximumPoolSize, a new thread is created.
4. If the queue is full and active threads == maximumPoolSize, the rejection policy is triggered.
Code Walkthrough
This program shows how to configure a thread pool and shut it down cleanly.
import java.util.concurrent.*;public class ExecutorServiceDemo { public static void main(String[] args) { // Create pool using Executors utility ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) { int taskId = i; executor.submit(() -> { System.out.println("Executing Task " + taskId + " via " + Thread.currentThread().getName()); }); }
executor.shutdown(); // Refuses new tasks, completes existing ones try { if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); // Force cancel pending tasks } } catch (InterruptedException e) { executor.shutdownNow(); Thread.currentThread().interrupt(); } } }
Interview-Relevant Information
Q: What is the difference between shutdown() and shutdownNow()?
Answer: shutdown() is graceful: it rejects new submissions but allows already-submitted tasks (both active and in the queue) to finish. shutdownNow() attempts to stop actively executing tasks by sending them an interrupt signal, discards queued tasks, and returns the list of unexecuted tasks.
Quick Checklist
How does the ThreadPoolExecutor decide whether to queue a task or create a thread? What is a rejection policy? If yes, you understand ExecutorService.
Use Cases
Managing request execution pipelines inside concurrent web servers.
Parallelizing microservice network calls to aggregate response data.
Common Mistakes
Using Executors.newCachedThreadPool() for high-traffic workloads. It allows infinite thread creation, leading to CPU overload and OOM errors.
Forgetting to call shutdown() on executors, causing threads to remain active and leaking memory.