Hirestack
Hirestack
Chapter 17

Problem 13: Design a Thread Pool

📖 2 min read · 4 sections · May 2026
Asked at: Amazon Microsoft

The setup

"Implement a thread pool. Fixed number of worker threads. Accepts tasks (Runnables). Tasks queue if all workers are busy. Support shutdown."

Core design

class ThreadPool {
  private final BlockingQueue taskQueue;
  private final List workers;
  private volatile boolean shutdown;
  
  public ThreadPool(int poolSize) {
    this.taskQueue = new LinkedBlockingQueue<>();
    this.workers = new ArrayList<>(poolSize);
    for (int i = 0; i < poolSize; i++) {
      WorkerThread w = new WorkerThread();
      workers.add(w);
      w.start();
    }
  }
  
  public void submit(Runnable task) {
    if (shutdown) throw new RejectedExecutionException();
    taskQueue.offer(task);
  }
  
  public void shutdown() {
    shutdown = true;
    workers.forEach(Thread::interrupt);
  }
  
  public void awaitTermination() throws InterruptedException {
    for (WorkerThread w : workers) w.join();
  }
  
  private class WorkerThread extends Thread {
    public void run() {
      while (!shutdown || !taskQueue.isEmpty()) {
        try {
          Runnable task = taskQueue.poll(1, TimeUnit.SECONDS);
          if (task != null) {
            try { task.run(); }
            catch (Throwable t) { /* log */ }
          }
        } catch (InterruptedException e) {
          if (shutdown) break;
        }
      }
    }
  }
}

Design Decision: bounded vs unbounded queue

LinkedBlockingQueue (unbounded) means accepted tasks accumulate without limit — OOM risk under sustained overload. Better: bounded queue with a rejection policy.

// Bounded queue with rejection
this.taskQueue = new ArrayBlockingQueue<>(maxQueueSize);

public void submit(Runnable task) {
  if (!taskQueue.offer(task)) {
    // Rejection: caller-runs, drop, log, exception
    rejectionPolicy.handle(task, this);
  }
}

Java's ThreadPoolExecutor has these built in. For implementation interviews, demonstrate awareness.

Takeaway

Thread pools are a foundational concurrency primitive. The interview test is whether you understand: bounded queues prevent OOM; rejection policies handle overflow; worker threads must respect interrupts for clean shutdown; tasks should be Runnable / Callable (not coupled to specific code).