Java Thread Pool | Executor, ExecutorService, Example

In this tutorial, we will learn Java thread pool. It is an ideal way to manage the number of tasks executing concurrently.

Thread Pool comes in Java 5.0 version with its own thread pool implementation. It is present in java.util.concurrent package.

A thread pool in Java is a common multithreaded design pattern. It is a collection of several worker threads that waits for tasks to perform. It contains a queue that keeps tasks waiting to get executed.

In other words, a thread pool is basically a group of threads that are used to perform multiple tasks in the background simultaneously.

A thread pool may contain a number of threads where each thread will perform a specific job. When a task is sent to the thread pool, one of the available worker threads process it.

If all worker threads in the thread pool are busy in performing their tasks, a new task that needs to be processed, either additional worker threads are created to handle incoming tasks, or tasks are waiting in a queue until worker threads are available or free.

When a thread in the thread pool completes the processing of task, it waits in a queue for performing another task. In this way, thread in the thread pool can be reused for doing different tasks.

The reusability of thread helps to avoid creating a new thread for every task. Look at the below figure to understand better.

Java thread Pool

Executor in Java


Java implements a thread pool based on an executor that is present in java.util.concurrent package. It is an interface that is used for executing tasks in a thread pool. It is a useful design pattern for multithreaded programs.


Executor interface provides a method named execute(). The general syntax for using execute() method in a Java program is as follows:

Syntax:

public void execute(Runnable object)

This method executes the runnable task. We do not need to know about thread details associated with the task. Simply create the task and pass it to execute() method of an appropriate executor.

ExecutorService in Java


ExecutorService is a sub-interface of executor interface that is used for managing and controlling tasks. It is also present in java.util.concurrent package.

ExecutorService interface in Java provides four useful methods. They are:

1. shutdown(): This method is used to shut down the executor, but allow tasks in the executor to complete. Once the executor shuts down, it cannot accept new tasks.

The general syntax for using shutdown() method is as follows:

Syntax:

public void shutdown()

2. shutdownNow(): This method is used to shut down the executor immediately even though there are unfinished tasks in the pool. It also returns the list of uncompleted tasks. The general syntax is as follows:

Syntax:

public List<Runnable> shutdownNow()

3. isShutdown(): This method returns true if the executor has been shut down. The general syntax for using isShutdown() method is as follows:

Syntax:

public boolean isShutdown()

4. isTerminated(): This method returns true if all the tasks in the pool are terminated. The general form for this method is as follows:

Syntax:

public boolean isTerminated()

The difference between Executor interface and ExecutorService subinterface is that executor executes threads whereas executorservice manages threads.

How to create an Executor object in Java Program?


We can create an Executor object by using two static methods provided by Executors class. They are:

1. newFixedThreadPool(int): This method is used to create a fixed number of threads in a pool concurrently (simultaneously). If a thread completes executing a task, it can be recused to another task after its current task is completed.


The general syntax for using newFixedThreadPool() method is as follows:

Syntax:

public ExecutorService newFixedThreadPool(numberOfThreads int)

Suppose we are executing five tasks. So, let’s create an object of Executor having a fixed thread pool with a maximum of five threads.

ExecutorService executor  = Executors.newFixedThreadPool(5); // Line 1

It will create a thread pool executor with a total of five threads maximum.

Suppose we have replaced line 1 with

ExecutorService executor = Executors.newFixedThreadPool(1);

What will happen?

Since there is only one thread available in the thread pool, five runnable tasks will be executed sequentially.

2. newCachedThreadPool(): This method creates a new thread as needed if all threads in the pool are not idle and tasks are waiting for execution. However, previously constructed threads can be reused when they are available. The general syntax for using this method is:

Syntax:

public ExecutorService newCachedThreadPool()

If a thread is used within 60 seconds, it will be terminated from the cached pool. A cached pool may be an efficient way for many short tasks.

Let’s create an object of Executor using this method.

ExecutorService executor = Executors.newCachedThreadPool();

On using this method to create an object, new thread will be created for each waiting task so that tasks will be executed concurrently.

Java Thread Pool Example Program


Let’s take a simple example program where we will perform two tasks and submit tasks to thread pool. Here, we will create a fixed-size thread pool with a maximum of three threads. Look at the program source code to understand better.

Program code:

// A task for printing a character a specified number of times.
public class ThreadA implements Runnable
{
 private char charToPrint; // Declaration of instance variable to print character.
 public ThreadA(char c)
 {
  charToPrint = c;	 
 }
@Override
public void run()
{
 for(int i = 1; i <= 3; i++){
  System.out.println(charToPrint); 
 }
 }
}
// A task for printing number from 1 to n for a given value of n.
public class ThreadB implements Runnable
{
 private int n;
 public ThreadB(int n)
 {
  this.n = n;	 
 }
@Override 
public void run(){ 
for(int i = 1; i <= n; i++){
 System.out.println(i);	
  }
 }
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorDemo 
{
public static void main(String[] args) 
{
// Creating a fixed thread pool with maximum of three threads.	
 ExecutorService executor = Executors.newFixedThreadPool(3);
 
ThreadA t1 = new ThreadA('a'); 
ThreadA t2 = new ThreadA('b');
ThreadB t3 = new ThreadB(5);
 
// Submit tasks to thread pool.
   executor.execute(t1);
   executor.execute(t2);
   executor.execute(t3);
 
// Shut down the executor. 
   executor.shutdown();
  }
}
Output:
            a
            1
            b
            b
            b
            2
            3
            4
            5
            a
            a

As you can observe in the above program, a thread pool is used to perform multiple tasks in the background simultaneously. It contains three threads where each thread will perform a specific job. When a task is sent to the thread pool, one of the available worker threads process it.


Let’s modify the above program where the number of thread will be one and tasks will be three. In this case, tasks will be performed sequentially. Look at the source code.

Program code:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorDemo 
{
public static void main(String[] args) 
{
// Creating a fixed thread pool with maximum one thread.	
   ExecutorService executor = Executors.newFixedThreadPool(1);
 
   ThreadA t1 = new ThreadA('a'); 
   ThreadA t2 = new ThreadA('b');
   ThreadB t3 = new ThreadB(3);
 
// Submit tasks to thread pool.
   executor.execute(t1);
   executor.execute(t2);
   executor.execute(t3);
 
// Shut down the executor. 
    executor.shutdown();
  }
}
Output:
            a
            a
            a
            b
            b
            b
            1
            2
            3

As you can see that one thread in the thread pool can be reused for doing different tasks and the reusability of thread avoids creating a new thread for every task.

Program code:

// A task for performing the addition of two numbers.
public class Addition implements Runnable
{
 int a;
 int b;
 public Addition(int a, int b) {
   this.a = a;
   this.b = b;
 }
@Override
public void run()
{
  int sum = a + b;
  System.out.println("Sum: " +sum);
 }
}
// A task for performing subtraction of two numbers.
public class Subtraction implements Runnable
{
 int x;
 int y;
public Subtraction(int x, int y) {
  this.x = x;
  this.y = y;
 }
@Override
public void run()
{
  int sub = x - y;
  System.out.println("Sub: " +sub);
 }
}
// A task for performing multiplication of two numbers.
public class Multiplication implements Runnable
{
 int p;
 public Multiplication(int p) {
    this.p = p;
 }
@Override
public void run()
{
  int multiply = p * p;
  System.out.println("Multiply: " +multiply);
  }
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) 
{
// Creating a fixed thread pool with maximum one thread.	
   ExecutorService executor = Executors.newFixedThreadPool(1);

// Submit tasks to the thread pool.
   executor.execute(new Addition(25, 100)); 
   executor.execute(new Subtraction(10, 5));
   executor.execute(new Multiplication(5));
  
// Shut down the executor.    
   executor.shutdown();
 }
}
Output:
          Sum: 125
          Sub: 5
          Multiply: 25

Types of Thread Pool in Java


From JDK 1.5 onwards, Java API (Application Programming Interface) provides a framework named Executor that allows us to create different types of thread pool in Java programming. They are as follows:

1. Single Thread Pool: This thread pool is used to process one task at a time. In a single thread pool, we create only one thread and assign multiple tasks that will be performed sequentially.

2. Fixed Thread Pool: In a fixed thread pool, we create a fixed number of threads in the thread pool as per the requirement of tasks. All tasks are performed simultaneously.

3. Cached Thread Pool: It is an expandable thread pool that is suitable for those applications that have many short lived tasks.

Use of Thread Pool in Java


1. A Thread pool is used to avoid creating a new thread to perform each task.

2. It can be used to execute tasks efficiently.

3. The realtime use of Thread pool is in Servlet and JSP where the container creates a thread pool to process requests.

Advantage of Thread Pool in Java


The advantages of using thread pool in Java programming is as follows:

1. Thread pool saves time and gives better performance because there is no need to create new thread for other tasks that are waiting in a queue.

2. It enables a loosely coupled design by decoupling the creation and execution of tasks.

We know that a process can create only a limited number of threads. Creating so many threads can be expensive in terms of time and resources. If we create a thread at the time of request processing, it will slow down response time.

To overcome these issues, a pool of thread is created during the start-up of application, and threads are reused for request processing. This pool of thread is known as thread pool in Java and threads are known as worker threads.


Hope that this tutorial has covered all important points related to Thread pool, types of Thread pool, Executor, ExecutorService with example programs.
Thanks for reading!!!
Next ⇒ Thread Exception in Java⇐ PrevNext ⇒

Please share your love