Fixed Thread Pool in Java

A fixed thread pool maintains a bounded number of worker threads while additional submitted tasks wait until a worker becomes available. In Java, `Executors.newFixedThreadPool(n)` provides a common way to create one.

A fixed thread pool has a configured number of worker threads, such as `4`. When tasks are submitted, idle workers execute them immediately; when all workers are busy, newly submitted tasks wait in the executor's work queue.

The pool separates task submission from thread creation. Instead of creating a new thread for every task, callers submit `Runnable` or `Callable` work to an `ExecutorService`, which manages the worker threads.

With `Executors.newFixedThreadPool(n)`, the pool maintains up to `n` worker threads for submitted work. If a worker terminates because of an unexpected failure, the executor can replace it so the configured pool size can be maintained.

A fixed pool limits concurrent task execution, which can prevent an application from creating an unbounded number of threads. However, the queue used by this convenience factory is unbounded, so limiting worker count does not by itself limit the number of queued tasks.

Applications should eventually shut down an executor that is no longer needed. `shutdown()` stops accepting new tasks while allowing already-submitted work to finish; `shutdownNow()` attempts to interrupt running tasks and returns tasks that had not started.

Key points

Interview questions

What is a fixed thread pool?

A fixed thread pool is an executor with a configured number of worker threads. Submitted tasks are assigned to available workers, while tasks submitted when all workers are busy wait in a queue. This allows an application to control the number of tasks executing concurrently. In Java, `Executors.newFixedThreadPool(n)` is a common factory for this pattern.

What happens when you submit more tasks than the pool has threads?

Tasks that cannot immediately obtain a worker are placed in the executor's work queue. As workers finish existing tasks, they take pending tasks from the queue. Therefore, the pool limits active execution rather than automatically limiting the number of submitted tasks. With `newFixedThreadPool`, that queue is unbounded.

Why use a thread pool instead of creating a new thread for every task?

Creating threads has overhead and allowing unrestricted thread creation can exhaust system resources under load. A thread pool reuses worker threads and places a bound on concurrent execution. It also provides a standard abstraction for submitting tasks and managing their lifecycle. The appropriate pool configuration still depends on workload characteristics.

Does a fixed thread pool guarantee that tasks execute in submission order?

No, a fixed thread pool does not generally guarantee that tasks complete in submission order. Multiple workers can execute tasks concurrently, and task duration and scheduling can differ. Even if tasks are taken from the queue in a particular order, their completion and output order can differ. Code requiring ordering should enforce that requirement explicitly.

What are the shutdown semantics of `shutdown()` and `shutdownNow()`?

`shutdown()` prevents new task submissions while allowing previously submitted tasks to complete. `shutdownNow()` attempts to stop execution by interrupting running worker threads and returns tasks that had not started. An interrupt is cooperative, so a task that ignores interruption may continue running. Production code should therefore design long-running tasks to respond appropriately to interruption.