Multithreading
Thread Pool
Understand thread reuse, worker threads, and task queue configurations.
Interview: Tests understanding of thread pools, and the advantages of thread pools over raw thread creation.
Creating a thread is expensive because it requires allocating OS memory, native resources, and runtime stacks. A thread pool optimizes execution by maintaining a collection of pre-instantiated worker threads that consume tasks from a shared queue.
Core Idea
A thread pool decouples task submission from thread execution, recycling worker threads rather than destroying them.
Why It Matters
Reusing threads prevents JVM OutOfMemoryErrors (OOM) caused by unconstrained thread creation.
Interview Lens
Expect design questions on how you would implement a basic custom thread pool using a blocking queue.
Mechanics of a Thread Pool
A standard thread pool consists of:
- Worker Threads: A set of threads that run in loops, continuously polling a task queue for work.
- Task Queue: A blocking queue that holds tasks submitted to the pool when all worker threads are busy.
- Task Submission: Callers submit tasks (implementing
RunnableorCallable) to the pool.
Code Walkthrough
This is a basic implementation of a custom thread pool using standard queue synchronization.
import java.util.LinkedList; import java.util.Queue;public class CustomThreadPool { private final Queue<Runnable> taskQueue = new LinkedList<>(); private final Worker[] threads;
public CustomThreadPool(int poolSize) { threads = new Worker[poolSize]; for (int i = 0; i < poolSize; i++) { threads[i] = new Worker(); threads[i].start(); } }
public void execute(Runnable task) { synchronized (taskQueue) { taskQueue.add(task); taskQueue.notify(); // Wake up idle worker thread } }
private class Worker extends Thread { public void run() { Runnable task; while (true) { synchronized (taskQueue) { while (taskQueue.isEmpty()) { try { taskQueue.wait(); // Wait for task submission } catch (InterruptedException e) { return; } } task = taskQueue.poll(); } try { task.run(); // Execute task } catch (RuntimeException e) { // Prevent thread death on user exceptions } } } } }
Interview-Relevant Information
Q: Why should you avoid creating threads manually in enterprise Java?
Answer: Creating threads manually is an anti-pattern. Threads consume stack memory (often 1MB per thread). If request volume spikes, the system can run out of memory. Thread pools limit the maximum concurrency, handle resource reuse, and queue additional load.
Quick Checklist
Do you know why creating threads manually is bad? Can you explain the components of a thread pool? If yes, you understand thread pooling.
Use Cases
Managing database connection pools or processing HTTP requests in web servers.
Running concurrent calculation jobs on multi-core systems.
Common Mistakes
Not catching exceptions inside worker loops, causing worker threads to die silently.
Leaving the pool active when shutting down, preventing JVM exit.