Advanced Java October 06 ,2025

 

Implementing a Custom Thread Pool Using LinkedBlockingQueue in Java

Complete Step-by-Step Guide

Introduction

A Thread Pool is a collection of pre-created worker threads that execute tasks from a shared queue.
Instead of creating a new thread for every task (which is costly in terms of performance), a thread pool reuses threads, reducing overhead and improving efficiency.

Java provides ExecutorService as its thread pool implementation, but building a custom thread pool helps us understand:

  • How threads can be reused.
  • How tasks can be queued and processed.
  • How thread lifecycle management works.

In this blog, we will build a CustomThreadPool using our previously implemented CustomLinkedBlockingQueue.

Step-by-Step Implementation

Step 1 — Understand Requirements

Our custom thread pool must:

  1. Maintain a fixed number of worker threads.
  2. Use a task queue to store incoming tasks.
  3. Assign tasks to available threads.
  4. Allow graceful shutdown of the pool.
  5. Handle synchronization between threads.

Step 2 — Create the Worker Thread

Each worker thread repeatedly fetches tasks from the queue and executes them.

class Worker extends Thread {
    private final CustomLinkedBlockingQueue taskQueue;
    private volatile boolean isRunning = true;

    public Worker(CustomLinkedBlockingQueue taskQueue) {
        this.taskQueue = taskQueue;
    }

    @Override
    public void run() {
        while (isRunning) {
            try {
                Runnable task = taskQueue.take();
                task.run();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }

    public void shutdown() {
        isRunning = false;
        this.interrupt();
    }
}

Step 3 — Create the CustomThreadPool Class

This class manages workers and a shared queue for tasks.

public class CustomThreadPool {
    private final CustomLinkedBlockingQueue taskQueue;
    private final Worker[] workers;

    public CustomThreadPool(int poolSize, int queueCapacity) {
        taskQueue = new CustomLinkedBlockingQueue<>(queueCapacity);
        workers = new Worker[poolSize];

        for (int i = 0; i < poolSize; i++) {
            workers[i] = new Worker(taskQueue);
            workers[i].start();
        }
    }

    public void execute(Runnable task) throws InterruptedException {
        taskQueue.put(task);
    }

    public void shutdown() {
        for (Worker worker : workers) {
            worker.shutdown();
        }
    }
}

Step 4 — Test the CustomThreadPool

We will test by submitting tasks and letting worker threads process them.

public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
        CustomThreadPool threadPool = new CustomThreadPool(3, 5);

        for (int i = 1; i <= 10; i++) {
            final int taskNumber = i;
            threadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " executing task " + taskNumber);
                try {
                    Thread.sleep(1000); // simulate work
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        Thread.sleep(8000); // wait for tasks to complete
        threadPool.shutdown();
    }
}

Step 5 — Expected Output

Thread-0 executing task 1
Thread-1 executing task 2
Thread-2 executing task 3
Thread-0 executing task 4
Thread-1 executing task 5
...

Explanation:

  • Worker threads continuously pull tasks from the queue.
  • Tasks are processed in FIFO order.
  • Threads are reused instead of being created anew for every task.

Step 6 — Add Graceful Shutdown

To ensure that threads stop after completing tasks, we modify the shutdown method:

public void shutdownGracefully() {
    for (Worker worker : workers) {
        worker.shutdown();
    }
}

Worker threads exit when isRunning becomes false.

Complete code

// Node class for the queue
class Node {
    T item;
    Node next;

    Node(T item) {
        this.item = item;
        this.next = null;
    }
}

// Custom LinkedBlockingQueue implementation
class CustomLinkedBlockingQueue {
    private Node head;
    private Node tail;
    private int size;
    private final int capacity;

    public CustomLinkedBlockingQueue(int capacity) {
        this.capacity = capacity;
        head = tail = new Node<>(null); // dummy node
    }

    // Add task to queue (blocks if full)
    public synchronized void put(T item) throws InterruptedException {
        while (size == capacity) {
            wait();
        }
        Node newNode = new Node<>(item);
        tail.next = newNode;
        tail = newNode;
        size++;
        notifyAll(); // notify waiting threads
    }

    // Take task from queue (blocks if empty)
    public synchronized T take() throws InterruptedException {
        while (size == 0) {
            wait();
        }
        Node first = head.next;
        head.next = first.next;
        size--;
        if (size == 0) {
            tail = head; // reset tail
        }
        notifyAll(); // notify producers
        return first.item;
    }

    public synchronized int size() {
        return size;
    }
}

// Worker thread that executes tasks
class Worker extends Thread {
    private final CustomLinkedBlockingQueue taskQueue;
    private volatile boolean isRunning = true;

    public Worker(CustomLinkedBlockingQueue taskQueue) {
        this.taskQueue = taskQueue;
    }

    @Override
    public void run() {
        while (isRunning) {
            try {
                Runnable task = taskQueue.take();
                task.run();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }

    public void shutdown() {
        isRunning = false;
        this.interrupt();
    }
}

// Custom Thread Pool implementation
class CustomThreadPool {
    private final CustomLinkedBlockingQueue taskQueue;
    private final Worker[] workers;

    public CustomThreadPool(int poolSize, int queueCapacity) {
        taskQueue = new CustomLinkedBlockingQueue<>(queueCapacity);
        workers = new Worker[poolSize];

        for (int i = 0; i < poolSize; i++) {
            workers[i] = new Worker(taskQueue);
            workers[i].start();
        }
    }

    public void execute(Runnable task) throws InterruptedException {
        taskQueue.put(task);
    }

    public void shutdown() {
        for (Worker worker : workers) {
            worker.shutdown();
        }
    }

    public void shutdownGracefully() {
        shutdown();
    }
}

// Test class
public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
        CustomThreadPool threadPool = new CustomThreadPool(3, 5);

        for (int i = 1; i <= 10; i++) {
            final int taskNumber = i;
            threadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " executing task " + taskNumber);
                try {
                    Thread.sleep(1000); // simulate work
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        Thread.sleep(8000); // wait for some tasks to complete
        threadPool.shutdownGracefully();
    }
}

How it works:

  • CustomLinkedBlockingQueue handles task storage safely using wait() and notifyAll().
  • Worker threads continuously take tasks from the queue and execute them.
  • CustomThreadPool manages worker lifecycle and task submission.
  • The main test submits 10 tasks to a pool of 3 threads, demonstrating thread reuse and queue-based execution.

 Real-World Use Case

Custom thread pools are useful for:

  • Web servers processing multiple requests.
  • Batch processing systems.
  • Applications with predictable, recurring tasks.
  • Background job execution.

 Advantages

  1. Performance improvement: Thread reuse reduces creation overhead.
  2. Resource management: Controls the number of concurrent threads.
  3. Task scheduling: Centralized queue allows orderly task execution.

 Disadvantages

  1. Implementation complexity: More code to maintain compared to built-in thread pools.
  2. Synchronization overhead: Managing threads and queues requires careful synchronization.
  3. Shutdown handling: Requires explicit management to stop threads gracefully.

 Summary

The custom thread pool is an essential multithreading concept that shows how threads can be reused to efficiently handle multiple tasks.
By implementing it step-by-step, we learned how to:

  • Maintain a fixed number of worker threads.
  • Use a shared blocking queue to manage tasks.
  • Synchronize threads to prevent race conditions.
  • Gracefully shut down the pool.

This approach significantly improves application performance by avoiding the cost of creating and destroying threads repeatedly. The custom thread pool also demonstrates how to coordinate worker threads and tasks effectively.

Although Java provides the ExecutorService and ThreadPoolExecutor classes as robust thread pool implementations, creating a custom thread pool builds a deeper understanding of thread management, task queuing, and blocking behavior. Such knowledge is critical for designing high-performance multithreaded systems and forms the foundation for advanced concurrency programming.

 

Sanjiv
0

You must logged in to post comments.

Related Blogs

Generics P...
Advanced Java August 08 ,2025

Generics Part- 2

Collection...
Advanced Java July 07 ,2025

Collections Framewor...

Mastering...
Advanced Java August 08 ,2025

Mastering Java Multi...

Annotation...
Advanced Java August 08 ,2025

Annotations

Java Multi...
Advanced Java August 08 ,2025

Java Multithreading...

Java Memor...
Advanced Java August 08 ,2025

Java Memory Manageme...

Java Lambd...
Advanced Java August 08 ,2025

Java Lambda Expressi...

Java Funct...
Advanced Java August 08 ,2025

Java Functional Inte...

Java Strea...
Advanced Java August 08 ,2025

Java Stream API

JDBC (Java...
Advanced Java August 08 ,2025

JDBC (Java Database...

JDBC (Java...
Advanced Java September 09 ,2025

JDBC (Java Database...

Annotation...
Advanced Java August 08 ,2025

Annotations

Generics
Advanced Java August 08 ,2025

Generics

Java I/O (...
Advanced Java August 08 ,2025

Java I/O (NIO)

Introducti...
Advanced Java September 09 ,2025

Introduction to Desi...

Design Pat...
Advanced Java September 09 ,2025

Design Patterns in J...

Other Prin...
Advanced Java September 09 ,2025

Other Principles Beh...

Creational...
Advanced Java September 09 ,2025

Creational Design Pa...

In Creatio...
Advanced Java September 09 ,2025

In Creational Design...

In Creatio...
Advanced Java September 09 ,2025

In Creational Design...

Creational...
Advanced Java September 09 ,2025

Creational Design Pa...

Structural...
Advanced Java September 09 ,2025

Structural Design Pa...

In Creatio...
Advanced Java September 09 ,2025

In Creational Design...

Structural...
Advanced Java September 09 ,2025

Structural Design Pa...

Builder De...
Advanced Java September 09 ,2025

Builder Design Patte...

Structural...
Advanced Java September 09 ,2025

Structural Design Pa...

Structural...
Advanced Java September 09 ,2025

Structural Design Pa...

Structural...
Advanced Java September 09 ,2025

Structural Design Pa...

Structural...
Advanced Java September 09 ,2025

Structural Design Pa...

Structural...
Advanced Java September 09 ,2025

Structural Design Pa...

Structural...
Advanced Java September 09 ,2025

Structural Design Pa...

Design Pat...
Advanced Java September 09 ,2025

Design Patterns in J...

Chain of R...
Advanced Java September 09 ,2025

Chain of Responsibil...

Command De...
Advanced Java September 09 ,2025

Command Design Patte...

Interprete...
Advanced Java September 09 ,2025

Interpreter Design P...

Iterator D...
Advanced Java September 09 ,2025

Iterator Design Patt...

Mediator D...
Advanced Java September 09 ,2025

Mediator Design Patt...

Memento De...
Advanced Java September 09 ,2025

Memento Design Patte...

Observer D...
Advanced Java September 09 ,2025

Observer Design Patt...

State Desi...
Advanced Java September 09 ,2025

State Design Pattern...

Strategy D...
Advanced Java September 09 ,2025

Strategy Design Patt...

Template M...
Advanced Java September 09 ,2025

Template Method Desi...

Visitor De...
Advanced Java September 09 ,2025

Visitor Design Patte...

Prototype...
Advanced Java September 09 ,2025

Prototype Design Pat...

Java 8+ Fe...
Advanced Java October 10 ,2025

Java 8+ Features

SOLID Prin...
Advanced Java October 10 ,2025

SOLID Principles in...

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

How Iterat...
Advanced Java October 10 ,2025

How Iterators Work i...

How Concur...
Advanced Java October 10 ,2025

How ConcurrentHashMa...

Comparable...
Advanced Java October 10 ,2025

Comparable vs Compar...

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

Semaphore...
Advanced Java October 10 ,2025

Semaphore in Java

ExecutorSe...
Advanced Java October 10 ,2025

ExecutorService in J...

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

Producer-C...
Advanced Java October 10 ,2025

Producer-Consumer Pr...

Busy Spin
Advanced Java October 10 ,2025

Busy Spin

Serializat...
Advanced Java October 10 ,2025

Serialization and De...

Segment Lo...
Advanced Java October 10 ,2025

Segment Locking in J...

Tree Bins...
Advanced Java October 10 ,2025

Tree Bins in Java

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

Custom Imp...
Advanced Java October 10 ,2025

Custom Implementatio...

Get In Touch

G06, Kristal Olivine Bellandur near Bangalore Central Mall, Bangalore Karnataka, 560103

+91-8076082435

techiefreak87@gmail.com