Sunday, September 17, 2023

How to create Thread Pool in Java using Executor Framework - Example Tutorial

Java 1.5 introduced a Thread pool in Java in the form of an Executor framework, which allows Java programmers to decouple submission of a task to the execution of the task. If you are doing server-side programming in Java then the Thread pool is an important concept to maintain scalability, robustness, and stability of the system. For those, who are not familiar with thread pool in Java or the concept of thread pool here is a one-liner, Thread pool in Java is a pool of worker threads, which is ready to perform any task given to them, mostly in the form of implementation of Runnable or Callable interface.

Since Java supports multithreading in the programming language itself, it allows multiple threads to run concurrently and perform parallel processing of the task.


In this article, we will learn the following things about thread pool in Java :
  1. What is a Thread pool in Java?
  2. Why do we need a Thread pool in Java?
  3. What is the Executor framework in Java 5?
  4. How to create a fixed-size thread pool using the Executor framework in Java?
  5. Benefits of using Thread Pool in Java?

And, if you are serious about mastering Java multi-threading and concurrency then I also suggest you take a look at these best Java Multithreading and Concurrency courses from Coursera and Udemy. It's an advanced course to become an expert in Multithreading, concurrency, and Parallel programming in Java with a strong emphasis on high performance


What is Thread Pool in Java and why do we need it?

As I said Thread pool is a pool of already created worker thread ready to do the job. The thread pool is one of the essential facilities any multi-threaded server-side Java application requires. 

One example of using a thread pool is creating a web server, which processes client requests. If you are familiar with socket programming then you know that ServerSocket.accept() is a blocking method and blocks until a socket connection is made. 



If only one thread is used to process client requests then it subsequently limits how many clients can access the server concurrently. In order to support a large number of clients, you may decide to use one thread per request paradigm, in which each request is processed by a separate thread, but this requires Thread to be created when the request arrived. 

Since the creation of Thread is a time-consuming process, it delays request processing. 

It also limits the number of clients based upon how many threads per JVM is allowed, which is obviously a limited number. Thread pool solves this problem for you, It creates Threads and manages them. Instead of creating Thread and discarding them once the task is done, thread-pool reuses threads in form of a worker thread. 

Since threads are usually created and pooled when the application starts, your server can immediately start request processing, which can further improve the server’s response time. Apart from this, there are several other benefits of using the Thread pool in Java applications, which we will see in a subsequent section. 

In short, we need thread pools to better manage threads and decouple task submission from execution. The thread pool and Executor framework introduced in Java 5 is an excellent thread pool provided by the library.


Java Thread Pool - Executor Framework in Java

Java 5 introduced several useful features like Enum, Generics, Variable arguments, and several concurrency collections and utilities like ConcurrentHashMap and BlockingQueue, etc, It also introduced a full feature built-in Thread Pool framework commonly known as Executor framework

The core of this thread pool framework is Executor interface which defines an abstraction of task execution with method execute(Runnable task) and ExecutorService which extends Executor to add various life-cycle and thread pool management facilities like shutting down thread pool. 

Executor framework also provides a static utility class called Executors ( similar to Collections) which provides several static factory methods to create various types of Thread Pool implementation in Java e.g. fixed-size thread pool, cached thread pool, and scheduled thread pool. Runnable and Callable interfaces are used to represent tasks executed by worker thread managed in these Thread pools. 


An interesting point about the Executor framework is that it is based on Producer consumer design pattern, where the application thread produces task and worker thread consumers or execute those task.

So it also suffers from the limitation of Producer consumer tasks like if production speed is substantially higher than consumption then you may run OutOfMemory because of the queued task, of course only if your queue is unbounded.


Java Thread Pool Example Executor Framework




How to create a fixed-size thread pool using the Executor framework in Java

Creating a fixed-size thread pool using Java 5 Executor framework is pretty easy because of static factory methods provided by the Executors class. All you need to do is define the task which you want to execute concurrently and then submit that task to ExecutorService.

After that Thread pool will take care of how to execute that task, it can be executed by any free worker thread and if you are interested in the result you can query the Future object returned by submit() method. 

The Executor framework also provides different kinds of Thread Pools like the SingleThreadExecutor which creates just one worker thread or CachedThreadPool which creates worker threads as and when necessary. 

You can also check  Java documentation of the Executor Framework for complete details of services provided by this API. Java concurrency in Practice also has a couple of chapters dedicated to the effective use of the Java 5 Executor framework, which is worth reading for any senior Java developer.



Example of Thread Pool in Java

Here is an example of the Thread pool in Java, which uses the Executor framework of Java 5 to create a fixed thread pool with a number of worker threads as 10. It will then create a task and submit that to the Thread pool for execution:

public class ThreadPoolExample {

    public static void main(String args[]) {
       ExecutorService service = Executors.newFixedThreadPool(10);
       for (int i =0; i<100; i++){
           service.submit(new Task(i));
       }
    }
  
}

final class Task implements Runnable{
    private int taskId;
  
    public Task(int id){
        this.taskId = id;
    }
  
    @Override
    public void run() {
        System.out.println("Task ID : " + this.taskId +" performed by " 
                           + Thread.currentThread().getName());
    }
  
}

Output:
Task ID : 0 performed by pool-1-thread-1
Task ID : 3 performed by pool-1-thread-4
Task ID : 2 performed by pool-1-thread-3
Task ID : 1 performed by pool-1-thread-2
Task ID : 5 performed by pool-1-thread-6
Task ID : 4 performed by pool-1-thread-5

If you look at the output of this Java example you will find different threads from thread pool are executing tasks.

Benefits of Thread Pool in Java

Thread Pool offers several benefits to Java applications, the biggest of them is separating submission of a task to execution of the task, which results in more loosely coupled and flexible design than tightly coupled create and execute the pattern. Here are some more benefits of using Thread pool in Java:

1) Use of Thread Pool reduces response time by avoiding thread creation during request or task processing.
2) Use of Thread Pool allows you to change your execution policy as you need. you can go from a single thread to multiple threads by just replacing ExecutorService implementation.

3) Thread Pool in Java application increases the stability of the system by creating a configured number of threads decided based on system load and available resources.

4) Thread Pool frees application developers from thread management stuff and allows them to focus on business logic.


That's all on the Thread pool and Executor Framework in Java. we have seen what is a thread pool in Java, what is executor framework in java 5, how to create a thread pool in Java, and some benefits of using a thread pool in Java application. no doubt knowledge of thread pool is essential for a server-side core Java developer and I suggest reading Java Threads and Concurrency Practice in Java to learn more about concurrency and thread pool.

Other Java Multithreading and Concurrency tutorials you may like
  • How to use the CountDownLatch utility in Java? (example)
  • How to use Semaphore class in Java? (code sample)
  • What is happens-before in Java concurrency? (answer)
  • How to use Future and FutureTask class in Java? (solution)
  • Difference between volatile, atomic, and synchronized in Java (answer)
  • How to use a CyclicBarrier class in Java? (example)
  • How to use the Lock interface in multi-threaded programming? (code sample)
  • Difference between CyclicBarrier and CountDownLatch in Java? (answer)
  • how to do inter-thread communication using wait and notify? (solution)
  • ForkJoin vs Executor Framework in Java (fork-join example)
  • How to use ThreadLocal variables in Java? (example)
  • Top 5 Concurrent Collection classes from Java 5 and Java 6 (read here)
  • 10 Examples of ConcurrentHahsMap in Java (examples)
  • 10 Multi-threading and Concurrency Best Practices (best practices)
  • 50 Java Thread Questions for Senior and Experienced Programmers (questions)

Thanks for reading this article so far. If you like this Java Thread pool and Executor example then please share it with your friends and colleagues. If you have any questions or feedback then please drop a note. 

P.S. - If you are new to the Java Programming field and need a free course to learn essential Java multithreading tools, libraries, and concepts then I highly suggest you join this free Java Multithreading course for beginners. This is a free Udemy course to learn Java Multithreading from scratch.

Now, over to you? What is better to use in Java Executor Framework or ForkJoin Pool? Which one is your favorite?

8 comments :

vineet said...

Don't forget to call service.shutdown() on ExecutorService. Also why @Override on the run() gives a compile error.

wiserhawk said...

Thanks Javin, very nice article, this is really what I was looking from many days about executor framework. Good job done. Best of luck

Anonymous said...

what will happen if one of the thread in thread pool throws exception.

Anonymous said...

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

class Task implements Runnable {
private int id;

public Task(int id) {
this.id = id;
}

public void run() {
try {
//Thread.sleep(10000);
System.out.println(Thread.currentThread().getName() + "----" + id);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}

public class ThreadPool {

public static void main(String[] args) {
ExecutorService tPool = Executors.newFixedThreadPool(5);

for (int i = 0; i < 20; i++) {
tPool.submit(new Task(i));
}

tPool.shutdown();
try {
tPool.awaitTermination(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
}

}
}

Unknown said...

How to decide the threadPool size? What are the factors(memory, processor, task incoming rate to be processed by the worker threads) to be considered when we decide the threadPool size?

javin paul said...

@Sapna Uniyal
Two factors
- load, how much message you are receiving per second
- number of CPU to avoid thread context switch

Anonymous said...

I have very generic question: Can we use threads for CRUD(especially write operations) using executor service etc? I have not seen any enterprise level implementation for the same. In normal web applications also (developed using Spring MVC,JPA etc) when we get thousand of requests at a time, does Framework internally spawns the thread? or we should use some threading and synchronization mechanism. When does it make sense to use threading for insert operations? If yes, then how will you dotransaction management for the same (in JDBC or Hibernate etc)? If one thread fails is there any way to rollback other threads as well? In case of Hiberante, how we will ensure the sequence of PK as execution order of thread can be anything, say if we are using @Id and wants data to be inserted in certain order? Can anyone please provide the little code snippet for the same?

javin paul said...

Hello @Anonymous, there are a lot of concept there, let's go one by one
1. for 1000 request you don't need 1000 thread. Ideally framework create threads for you but that is controlled with some configuration.
2. For sync processing, one thread take request and complete until data is stored into DB And response is returned to client. In async, it hand-over to another pool of thread for DB insertion, which is again a fixed thread pool, ideally have same number of thread as DB connections

Post a Comment