Thread Pool in Java

Thread Pools are particularly useful when we need to limit the number of threads running concurrently in our application. There is a performance overhead involved with starting a new thread, and each thread is also allocated some memory space for its stack etc.

Instead of starting a new thread for every task to execute concurrently, the task can be passed to a pool of threads. When there are idle threads available in the pool, the task is assigned to one of them and executed. So, it saves time because there is no need to create new thread thereby improving the performance.

Thread pools are sometimes used in multi-threaded servers involving Servlet and JSP applications where web container creates a thread pool to process the request. Each connection that is arriving at the server via the computer network is wrapped as a task and passed on to a pool of threads. The threads in the pool will process the requests on these connections concurrently.

Java language comes with built-in thread pools in the java.util.concurrent package, so we don’t have to implement our own thread pool.

 

Example of Java Thread Pool

Basically, Java thread pool manages the pool of worker threads. It consists of a queue that keeps tasks waiting to get executed. We can use the ThreadPoolExecutor class to create thread pool in Java.

Thread pool actually manages the collection of Runnable threads. The worker threads execute Runnable threads from the waiting queue. The class named java.util.concurrent.Executors provides factory and support methods for java.util.concurrent.Executor interface to create the thread pool in Java.

Executors is a utility class in Java that also provides useful methods to work with ExecutorService, ScheduledExecutorService, ThreadFactory, and Callable classes using various factory methods.

The following application shows a simple example of Java thread pool using ExecutorService and Executors.

First, we need to create a Runnable class, named UserThread.java. Here, each object of the UserThread class denotes a worker thread.

UserThread.java

package test.example;

public class UserThread implements Runnable {

private String msg;

public UserThread(String s) {
this.msg = s;
}

@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" Starting. Message = " + msg);
doWork();
System.out.println(Thread.currentThread().getName()+" Ending.");
}

private void doWork() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

@Override
public String toString(){
return this.msg;
}

}

In the following program, we are creating a fixed-size thread pool of 7 worker threads. Then we are submitting 10 tasks to this pool, since the pool size is 7, it will start working on 7 tasks and other tasks will be in wait state, as soon as one of the task is finished, another task from the waiting queue will be picked up by worker thread and gets executed. Here is the program named ThreadPoolExample.java where we are creating fixed thread pool from the Executors framework.

ThreadPoolExample.java

package test.example;

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;

public class ThreadPoolExample {

public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(7);
for (int i = 0; i < 10; i++) {
Runnable user = new UserThread("" + i);
executor.execute(user);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("\nAll threads are finished..");
}
}

Output:

The program shows the following output sequence during runtime.

pool-1-thread-3 Starting. Message = 2
pool-1-thread-7 Starting. Message = 6
pool-1-thread-6 Starting. Message = 5
pool-1-thread-2 Starting. Message = 1
pool-1-thread-4 Starting. Message = 3
pool-1-thread-5 Starting. Message = 4
pool-1-thread-1 Starting. Message = 0
pool-1-thread-1 Ending.
pool-1-thread-2 Ending.
pool-1-thread-4 Ending.
pool-1-thread-4 Starting. Message = 8
pool-1-thread-2 Starting. Message = 9
pool-1-thread-5 Ending.
pool-1-thread-3 Ending.
pool-1-thread-6 Ending.
pool-1-thread-7 Ending.
pool-1-thread-1 Starting. Message = 7
pool-1-thread-1 Ending.
pool-1-thread-4 Ending.
pool-1-thread-2 Ending.

All threads are finished..

The output confirms that there are 7 threads in the pool named from “pool-1-thread-1” to “pool-1-thread-7” and they are responsible for executing the submitted tasks to the pool.

NOTE: Both these Java programs must be placed in the same package (e.g. test.example).