How to implement Thread pool in Java without executor framework

Carvia Tech | May 05, 2019 | 3 min read | 1,159 views


Thread pool executor requires a Queue for holding tasks and a collection of Worker Threads that will pick up tasks from the work queue start running them. Let us try to write our own simple Thread Pool Executor implementation. It is a typical Producer Consumer Problem statement.

threadpool executor
Custom ThreadPoolExecutor

Below Java Program provides basic implementation for a working proof of concept for a threadpool executor.

CustomThreadPoolExecutor Basic Implementation
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class CustomThreadPoolExecutor {
    private final BlockingQueue<Runnable> workerQueue;
    private final Thread[] workerThreads;

    public CustomThreadPoolExecutor(int numThreads) {
        workerQueue = new LinkedBlockingQueue<>();
        workerThreads = new Thread[numThreads];
        int i = 0;
        for (Thread t : workerThreads) {
            t = new Worker("Custom Pool Thread " + ++i);
            t.start();
        }
    }

    public void addTask(Runnable r) {
        try {
            workerQueue.put(r);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    class Worker extends Thread {
        public Worker(String name) {
            super(name);
        }

        public void run() {
            while (true) {
                try {
                    workerQueue.take().run();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        CustomThreadPoolExecutor threadPoolExecutor = new CustomThreadPoolExecutor(10);
        threadPoolExecutor.addTask(() -> System.out.println("First print task"));
        threadPoolExecutor.addTask(() -> System.out.println("Second print task"));
    }

}

The above program will create pool of 10 worker threads and initialize them all.

Explanation

We are using two classes from standard java library in this implementation:

LinkedBlockingQueue

An optionally-bounded blocking queue based on linked nodes. This queue orders elements FIFO (first-in-first-out). It is thread-safe in nature and acts as a temporary storage of runnable tasks that are due for execution.

Thread

All the threads get initilized and started at the creation of ThreadPoolExecutor. All threads listen on the shared workqueue for incoming tasks in never ending loop.

What we missed

An production grade implementation would have lot more sophistication than the basic implementation provided here, for example:

  1. Capability to tune number of items that can fit into queue.

  2. Capability to configure idle and max worker threads, incase of no work items, number of active threads will reduce to idle threads.

  3. Lazy initialization

  4. Proper exception handling is not implemented in this article

Production usage advise

Always use Executor Framework provided in java.util.concurrent package for executing tasks in your production code. It is simple to use, provides interface-based task execution facility and time tested.

ExecutorService example usage
ExecutorService exec = Executors.newSingleThreadExecutor();
exec.execute(runnable);
exec.shutdown();

Why do we need ThreadPool executor?

There are many reasons one would like to use threadpool executor:

  1. Creating and destroying threads is a IO extensive operation, which has impact on performance and memory consumption of an application. So its ideal to create threads once and reuse them later on.

  2. We do not want to run out of threads when heavy load arrives on an application. Threadpool holds tasks in a queue, so if lot of tasks arrives in a very short amount of time, queue will hold the tasks until a worker thread becomes available for the processing. This approach prevents resource exhaustion in production environment.

  3. If due to some reasons, thread gets killed, ThreadPoolExecutor will recreate the thread and put it back to the pool.


Top articles in this category:
  1. How to configure custom ThreadPool for Java 8 Stream API parallel operations
  2. What is Deadlock in Java? How to troubleshoot and how to avoid deadlock
  3. Difference between Implementing Runnable and Extending Thread
  4. How will you implement your custom threadsafe Semaphore in Java
  5. What is ThreadLocal in Java, where will you use this class
  6. How will you implement a Blocking Queue in Java
  7. What is difference between sleep() and wait() method in Java?



Find more on this topic:
Core Java image
Core Java

Core Java - OOP Concepts, Garbage Collection, Multi-threading, Collections Framework, Java 8 Features, Lambda Functions, Streams.

Last updated 1 week ago


Recommended books for interview preparation:

This website uses cookies to ensure you get the best experience on our website. more info