Skip to content

Thread pool

🧡 Thread Pools in Java

Imagine a kitchen with a fixed number of chefs 🍳 Orders (tasks) keep coming, but instead of hiring a new chef each time, you reuse the same team. That’s a thread pool.


🧠 What is a Thread Pool?

A thread pool is a collection of pre-created threads that execute tasks from a queue.

πŸ‘‰ Managed via ExecutorService and ThreadPoolExecutor

```java id="2m6t8p" ExecutorService pool = Executors.newFixedThreadPool(3);

---

## πŸ”„ How it works

```id="flow1"
Tasks β†’ Queue β†’ Thread Pool β†’ Execution

  1. You submit tasks
  2. Tasks go into a queue
  3. Threads pick tasks and execute
  4. Threads are reused

βš™οΈ Basic Example

```java id="ex1" ExecutorService pool = Executors.newFixedThreadPool(2);

for (int i = 1; i <= 5; i++) { int task = i; pool.submit(() -> { System.out.println("Task " + task + " by " + Thread.currentThread().getName()); }); }

pool.shutdown();

---

## πŸ—οΈ Types of Thread Pools

### 1. Fixed Thread Pool

```java id="tp1"
Executors.newFixedThreadPool(3);

  • Fixed number of threads
  • Extra tasks wait in queue

πŸ‘‰ Best for: controlled load


2. Cached Thread Pool

```java id="tp2" Executors.newCachedThreadPool();

* Creates threads as needed
* Reuses idle threads
* Can grow large ⚠️

πŸ‘‰ Best for: **short-lived tasks**

---

### 3. Single Thread Executor

```java id="tp3"
Executors.newSingleThreadExecutor();

  • Only one thread
  • Tasks executed sequentially

πŸ‘‰ Best for: ordered execution


4. Scheduled Thread Pool

```java id="tp4" Executors.newScheduledThreadPool(2);

* Runs tasks after delay or periodically

πŸ‘‰ Example:

```java id="tp5"
scheduler.schedule(() -> System.out.println("Run"), 2, TimeUnit.SECONDS);


πŸ”§ Core Components (under the hood)

ThreadPoolExecutor uses:

  • Core Pool Size β†’ minimum threads
  • Max Pool Size β†’ max threads
  • BlockingQueue β†’ holds tasks
  • RejectedExecutionHandler β†’ handles overflow

```java id="tp6" new ThreadPoolExecutor( 2, 4, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>() );

---

## 🚧 Rejection Policies

When queue is full:

* `AbortPolicy` β†’ throws exception
* `CallerRunsPolicy` β†’ caller thread runs task
* `DiscardPolicy` β†’ silently drops
* `DiscardOldestPolicy` β†’ removes oldest task

---

## βš”οΈ Why Thread Pool?

| Problem              | Without Pool | With Pool  |
|----------------------|--------------|------------|
| Thread creation cost | High         | Low        |
| Resource usage       | Uncontrolled | Controlled |
| Performance          | Poor         | Better     |
| Scalability          | Hard         | Easy       |

---

## 🎯 Real Use Cases

* Web servers (handle requests)
* APIs / microservices
* Background jobs
* File processing
* Async tasks

---

## ⚠️ Best Practices

* Always call:

```java id="tp7"
pool.shutdown();

  • Avoid newCachedThreadPool() in heavy systems
  • Prefer custom ThreadPoolExecutor for control

🧠 Interview Nuggets

  • Thread pool uses BlockingQueue internally
  • Threads are reused, not created every time
  • Prevents OutOfMemoryError (too many threads)

🧠 Memory Trick

Thread Pool = Reusable threads + Task queue πŸ§΅βž‘οΈπŸ“¦

🧡 Creation of Thread Pools (Deep Dive)

Think of a thread pool as a factory floor 🏭 You decide:

  • how many workers (threads)
  • how many jobs can wait (queue)
  • what happens when factory is overloaded

That factory is built using ThreadPoolExecutor.


🧠 1. High-Level Creation (Easy Way)

Using Executors

ExecutorService pool = Executors.newFixedThreadPool(3);

πŸ‘‰ This hides complexity πŸ‘‰ Internally uses ThreadPoolExecutor


πŸ”Ή Common factory methods

Executors.newFixedThreadPool(n);
Executors.newCachedThreadPool();
Executors.newSingleThreadExecutor();
Executors.newScheduledThreadPool(n);

πŸ‘‰ Good for quick usage πŸ‘‰ Not ideal for production (less control)


βš™οΈ 2. Real Creation (ThreadPoolExecutor)

This is where interviews live πŸ”₯

ThreadPoolExecutor pool = new ThreadPoolExecutor(
    corePoolSize,
    maximumPoolSize,
    keepAliveTime,
    TimeUnit.SECONDS,
    workQueue,
    threadFactory,
    rejectionHandler
);

🧩 Components Explained

1. 🧡 corePoolSize

πŸ‘‰ Minimum threads always alive

corePoolSize = 2;
  • Even if idle β†’ threads stay

2. πŸš€ maximumPoolSize

πŸ‘‰ Max threads allowed

maximumPoolSize = 4;
  • Used when queue is full

3. ⏱️ keepAliveTime

πŸ‘‰ Idle thread survival time

keepAliveTime = 60;
  • Extra threads die after this

4. πŸ“¦ workQueue (VERY IMPORTANT)

πŸ‘‰ Where tasks wait

new LinkedBlockingQueue<>();

Types:

  • LinkedBlockingQueue β†’ unbounded
  • ArrayBlockingQueue β†’ fixed size
  • SynchronousQueue β†’ no storage

5. 🏭 ThreadFactory

πŸ‘‰ Controls thread creation

Executors.defaultThreadFactory()

Used for:

  • Naming threads
  • Setting priority

6. 🚧 RejectedExecutionHandler

πŸ‘‰ What happens when pool is full

Options:

  • AbortPolicy β†’ throws exception
  • CallerRunsPolicy β†’ caller runs task
  • DiscardPolicy β†’ drops task
  • DiscardOldestPolicy β†’ removes oldest

πŸ”„ How ThreadPoolExecutor Works

This is the core algorithm 🧠

1. If threads < corePoolSize β†’ create thread
2. Else β†’ put task in queue
3. If queue full β†’ create thread (until maxPoolSize)
4. If still full β†’ reject task

πŸ§ͺ Example (Full Control)

ThreadPoolExecutor pool = new ThreadPoolExecutor(
    2,                          // core
    4,                          // max
    60, TimeUnit.SECONDS,       // keep alive
    new ArrayBlockingQueue<>(2) // queue
);

for (int i = 1; i <= 10; i++) {
    int task = i;
    pool.execute(() -> {
        System.out.println("Task " + task +
            " by " + Thread.currentThread().getName());
    });
}

🎯 Behavior of Above Example

  • First 2 tasks β†’ new threads
  • Next 2 β†’ queue
  • Next 2 β†’ new threads (max reached)
  • Remaining β†’ ❌ rejected

⚠️ Why NOT use Executors in production?

Example:

Executors.newFixedThreadPool(100);

πŸ‘‰ Uses unbounded queue

Risk:

  • Memory grows
  • Possible crash πŸ’₯

🧠 Best Practice

Always define:

new ThreadPoolExecutor(
    core,
    max,
    time,
    unit,
    new ArrayBlockingQueue<>(size)
);

πŸ‘‰ Controlled + predictable


πŸ”₯ Real Production Example

int cores = Runtime.getRuntime().availableProcessors();

ThreadPoolExecutor pool = new ThreadPoolExecutor(
    cores,
    cores * 2,
    60,
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100),
    Executors.defaultThreadFactory(),
    new ThreadPoolExecutor.CallerRunsPolicy()
);

βš”οΈ Summary

Component Purpose
corePoolSize base threads
maxPoolSize limit threads
queue task waiting
keepAlive idle cleanup
rejection overload handling

🧠 Memory Trick

ThreadPool = Threads + Queue + Rules πŸ§΅πŸ“¦βš™οΈ