Implementing Thread Pool In Java


Here is an example of a thread pool implementation in Java that includes thread pool shutdown and handling of interrupted exceptions:

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicBoolean;

public class ThreadPool {
    private final int poolSize;
    private final LinkedList<Runnable> tasks;
    private final Worker[] workers;
    private final AtomicBoolean running = new AtomicBoolean(true);

    public ThreadPool(int poolSize) {
        this.poolSize = poolSize;
        tasks = new LinkedList<>();
        workers = new Worker[poolSize];

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

    public void execute(Runnable task) {
        if (!running.get()) {
            throw new IllegalStateException("ThreadPool is not running");
        }

        synchronized (tasks) {
            tasks.addLast(task);
            tasks.notify();
        }
    }

    public void shutdown() {
        running.set(false);

        for (Worker worker : workers) {
            worker.interrupt();
        }
    }

    private class Worker extends Thread {
        @Override
        public void run() {
            while (running.get()) {
                Runnable task;
                synchronized (tasks) {
                    while (tasks.isEmpty() && running.get()) {
                        try {
                            tasks.wait();
                        } catch (InterruptedException e) {
                            if (!running.get()) {
                                return;
                            }
                        }
                    }

                    if (!running.get()) {
                        return;
                    }

                    task = tasks.removeFirst();
                }
                task.run();
            }
        }
    }
}

This code defines a ThreadPool class that can be used to execute multiple tasks concurrently. The class maintains a fixed-size pool of worker threads, where each thread repeatedly takes a task from the task queue and executes it.

When the ThreadPool is created, it creates the number of threads specified in the poolSize and starts each of them.

The execute method is used to add a task to the task queue. It uses an AtomicBoolean running to check if the thread pool is running, If the thread pool is not running it throws an exception. It also uses a synchronized block to ensure that only one thread can add a task to the queue at a time. When a task is added, the method notifies any threads that are waiting for tasks to become available.

The shutdown method is used to stop the thread pool. It sets the running variable to false and interrupts all worker threads. This causes the worker threads to break out of the task waiting loop and exit.

Each worker thread runs in a loop, repeatedly taking a task from the task queue and executing it. The worker thread uses a synchronized block to wait for tasks to become available if the task queue is empty. In the case of InterruptedException if the thread pool is running the worker waits for more tasks to come in, if the thread pool is not running the worker thread exits the loop.

Here is an example of how to use the previously defined ThreadPool class:

ThreadPool threadPool = new ThreadPool(5);

Runnable task1 = new Runnable() {
    @Override
    public void run() {
        // task1 logic here
    }
};

Runnable task2 = new Runnable() {
    @Override
    public void run() {
        // task2 logic here
    }
};

threadPool.execute(task1);
threadPool.execute(task2);

//... more tasks can be added to the thread pool using execute method

// shutdown the thread pool
threadPool.shutdown();

In this example, we first create a ThreadPool object with a pool size of 5. Then we create two Runnable objects that contain the logic for tasks that we want to execute. We then add these tasks to the thread pool by calling the execute method.

We can add more tasks to the thread pool using the execute method. Once all the tasks are added and processed, we can shutdown the thread pool using the shutdown method. Once the thread pool is shut down, it cannot accept any new tasks and all the worker threads will exit.

It's important to note that, the shutdown method only stop accepting new tasks and the already submitted task will be processed by the worker thread.