Java ThreadPoolExecutor example

Java 5 has introduced new concurrent API called “Executor frameworks” to make programmer life easy. It simplifies design and development of multi-thread applications. It consists of mainly Executor, ExecutorService interface and ThreadPoolExecutor class which implements both interfaces i.e. Executor and ExecutorService. ThreadPoolExecutor class provide the implementation of thread pool. We will understand more about it in the later part of the tutorial.

Why do we need Executor framework?

When we create a simple multi threading application, we create  Runnable objects and construct Thread object using Runnable, We need to create, execute and manage thread. It may be difficult for us to do that. Executor Framework does it for you. It is responsible for creating, executing and managing the thread and not only this, it improves the performance of the application too.
When you follow task per thread policy, you create a new thread for each task then if system is highly overloaded, you will get out of memory error and your system will fail. If you use ThreadPoolExecutor , you won’t create thread for new task. You will assign task to a limited number of threads once thread completes one task, it will be given another task.

Core interface of Executor framework is Executor. It has a method called “execute”.

There is another interface called ExecutorService which extends Executor interface. It can be termed as Executor that provides methods that can control termination and methods that can produce a Future for tracking the progress of one or more asynchronous tasks. It has method such as submit, shutdown, shutdownNow etc.
ThreadPoolExecutor is actual implementation of ThreadPool. It extends AbstractThreadPoolExecutor which implements ExecutorService interface. You can create ThreadPoolExecutor from factory methods of Executor class. It is recommended a way to get an instance of ThreadPoolExecutor.
There are 4 factory methods in Executors class which can be used to get an instance of ThreadPoolExecutor. We are using Executors’ newFixedThreadPool to get an instance of ThreadPoolExecutor.


Here are four factory method present in Executors class.
newFixedThreadPool: This method returns thread pool executor whose maximum size(let’s say n threads) is fixed.If all n threads are busy performing the task and additional tasks are submitted, then they will have to be in the queue until thread is available.
newCachedThreadPool: this method returns an unbounded thread pool. It doesn’t have maximum size but if it has less number of tasks, then it will tear down unused thread. If thread has been unused for 1 mins(keepAliveTime), then it will tear it down.
newSingleThreadedExecutor: this method returns an executor which is guaranteed to use the single thread. 
newScheduledThreadPool: this method returns a fixed size thread pool that can schedule commands to run after a given delay, or to execute periodically.

Let’s create a basic example of ThreadPoolExecutor and we will use newFixedThreadPool to create a instance of ThreadPoolExecutor.
Let’s create a Task. Here Task will be to read different files and process them.

Let’s create ThreadPoolExecutor which will consume above task and process it.

When you run above program, you will get below output:

We have used new newFixedThreadPool, so when we have submitted 10 task, 5 new threads will be created and will execute 5 tasks. Other 5 tasks will wait in wait queue. As soon as any task will be completed by thread, another task will be picked by this thread and will execute it.

Using constructor of ThreadPoolExecutor:

If you want to customize creation of ThreadPoolExecutor, you can use its constructors too.

corePoolSize: corePoolSize is the number of threads to keep in the pool, even if they are idle
MaximumPoolSize: the maximum number of threads to allow in the pool
keepAliveTime: When you have more threads already available than corePoolSize, then keepAliveTime is time upto which that thread will wait for task before terminating.
unit: time unit is for keepAliveTime
workQueue: workQueue is the BlockingQueue which holds the tasks before execution.
threadFactory: Factory which is used to create a new Thread.
handler : RejectedExecutionHandler which is used in case execution is block or queue is full. Lets create a RejectedExecutionHandler for handling rejected task.

Lets change to below code to make use of ThreadPoolExecutor constructor.

When you run above program, you will get below output:

If you notice here File 7, File 8, File 9 and File 10 got rejected. Lets understand why they got rejected. Max pool size in ThreadPoolExecutor’s Constructor is 2, so when we submitted 10 tasks to thread pool, 2 threads got created and started processing 2 tasks and 4 tasks got queued in LinkedBlockingQueue, so once LinkedBlockingQueue became full, rest tasks got rejected.

How to decide the size of thread pool:

You should not hardcode size of thread pool. It should be provided by configuration or calculated from Runtime.availableProcessors.
Thread size should not be too big or too small. If you choose thread pool size that is too big, then it will overload the system and will not work properly. If you choose thread pool size too small, it will affect throughput and performance.

Add Comment