Example of ThreadPoolExecutor in Java
March 11, 2013 | Modified on August 14, 2016
On this page we will provide example of ThreadPoolExecutor in java. ThreadPoolExecutor is a java concurrent API and has been introduced in JDK 1.5. ThreadPoolExecutor
is a ExecutorService
that executes submitted Runnable
task. ThreadPoolExecutor
is instantiated by passing core pool size, maximum pool size, idle thread alive time, time unit for alive time, BlockingQueue
, ThreadFactory
and RejectedExecutionHandler
. When a new request arrives, a new thread is created by ThreadPoolExecutor
to serve the request even if idle thread is there in pool. It happens till the ThreadPoolExecutor
achieves given core pool size. Thread is created by using ThreadFactory
. Idle thread alive time does not apply on idle threads if pool size is less than or equal to core pool size. Now if a request arrives and pool size is equal to core pool size then first idle thread will serve the request and if there is no idle thread only when a new thread is created up to the maximum thread pool size. When pool size is larger than core pool size then idle thread will die after given alive time to release the resources. No thread will be created if the pool size has reached up to the maximum pool size. Now if a request arrives and no thread is idle to serve the request, then all the subsequent request will go in queue. Once a thread from pool becomes idle, then request from queue will be served. If ThreadPoolExecutor
is unable to serve the request due to some reason then it throws RejectedExecutionException
. This request is handled by RejectedExecutionHandler
.
Contents
Instantiate ThreadPoolExecutor
We can instantiateThreadPoolExecutor
using the following constructor where ThreadFactory
and RejectedExecutionHandler
are optional parameters and default values are Executors.defaultThreadFactory()
and ThreadPoolExecutor.AbortPolicy
respectively.
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
int maximumPoolSize : When a request is made and all the threads in core pool size are busy then a new thread is created until it reached up the maximum pool size. After the maximum pool size, all the new request goes into queue.
long keepAliveTime: This is a waiting time for an idle thread to die. An idle thread dies after keepAliveTime only if the thread count is more than core pool size and less or equal to maximum core pool size.
TimeUnit unit: This is the time unit for keepAliveTime parameter.
BlockingQueue<Runnable> workQueue : It holds the task before it is executed. It will contain only
Runnable
task. BlockingQueue
is a queue such that if a thread wants to fetch an element and queue is empty then thread will be blocked and wait till the element gets available in queue. In the same way while adding element if there is no space in queue, thread will be blocked and wait to get space available.
ThreadFactory threadFactory : This is optional parameter. Pass the user defined
ThreadFactory
using which ThreadPoolExecutor
will create threads. By default Executors.defaultThreadFactory()
is used.
RejectedExecutionHandler handler: This is optional parameter.
ThreadPoolExecutor.execute()
can reject new task in two scenarios.
1. Executor has been shutdown.
2. Executor uses finite bounds for work queue capacity as well as maximum threads and they are saturated.
The rejected task is handled by
RejectedExecutionHandler
using following policies.
ThreadPoolExecutor.AbortPolicy
: It aborts the task and always throws RejectedExecutionException
.
ThreadPoolExecutor.CallerRunsPolicy
: It executes the rejected task itself.
ThreadPoolExecutor.DiscardPolicy
: It simply drops the task.
ThreadPoolExecutor.DiscardOldestPolicy
: In case when ThreadPoolExecutor.execute()
has rejected the task because of finite bounds of work queue and maximum limit, this policy simply drops the task at the head of the work queue. The default policy is ThreadPoolExecutor.AbortPolicy
.
Execute Task using ThreadPoolExecutor
ThreadPoolExecutor
provides execute()
method to run Runnable
task some times in future. The task will run either by a thread in the pool or by new thread. If thread pool rejects the task then it will be handled by RejectedExecutionHandler
. ThreadPoolExecutor
can be inherited to provide custom definition for the methods beforeExecute()
and afterExecute()
. beforeExecute()
is invoked before the given Runnable
task is executed and afterExecute()
is invoked upon the task completion.
Shutdown, Terminate and Remove Task in ThreadPoolExecutor
ThreadPoolExecutor
provides the following methods to shutdown, terminate and remove the tasks.
shutdown(): When this method is called,
ThreadPoolExecutor
starts shutting down in the order in which previously submitted task executed and no new task is accepted. It does not wait to complete the execution of previously submitted task.
shutdownNow(): It stops all actively executing tasks and also halts the processing of waiting tasks and returns the list of waiting tasks. They are removed from the queue as well. This method does not wait to terminate the actively executing tasks.
awaitTermination(): This methods blocks the shutdown request until all tasks have completed or timeout occurs or thread is interrupted. We need to pass maximum waiting time.
isShutdown(): Returns true if executor has been shutdown.
isTerminated(): Returns true if all tasks have followed shutdown.
purge(): It tries to removes all tasks from the work queue that have been cancelled.
remove(): It removes the given task from the internal queue of executor.
ThreadPoolExecutor setMaximumPoolSize() and getMaximumPoolSize() Example
Maximum pool size forThreadPoolExecutor
is assigned while instantiating using constructor but we can change the value at runtime too using the method given below.
setMaximumPoolSize(): Sets maximum allowed number of threads at runtime.
getMaximumPoolSize(): Fetches the maximum allowed number of threads in pool.
ThreadPoolExecutorDemoOne.java
package com.concretepage; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPoolExecutorDemoOne { public static void main(final String[] args) throws Exception { final ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 3, 100, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy()); executor.execute(new BookReader("Ramayan")); executor.execute(new BookReader("Mahabharat")); executor.execute(new BookReader("Veda")); System.out.println("Old Max Pool Size:"+ executor.getMaximumPoolSize()); executor.setMaximumPoolSize(4); System.out.println("New Max Pool Size:"+ executor.getMaximumPoolSize()); executor.shutdown(); } }
package com.concretepage; public class BookReader implements Runnable { private String bookName; public BookReader(String bookName) { this.bookName = bookName; } @Override public void run() { for(int i = 0; i<3; i++) { System.out.println("Reading book: "+ bookName); } } }
Reading book: Ramayan Reading book: Ramayan Reading book: Ramayan Reading book: Veda Reading book: Mahabharat Reading book: Mahabharat Reading book: Mahabharat Old Max Pool Size:3 Reading book: Veda Reading book: Veda New Max Pool Size:4
ThreadPoolExecutor setCorePoolSize(), getCorePoolSize() and getCompletedTaskCount() Example
Core pool size of work queue can also be changed at run time.setCorePoolSize() : Sets new core pool size at run time.
getCorePoolSize() : Fetches core pool size.
getCompletedTaskCount() : Returns completed task count.
ThreadPoolExecutorDemoTwo.java
package com.concretepage; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPoolExecutorDemoTwo { public static void main(final String[] args) throws Exception { final ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 100, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new MyThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy()); executor.execute(new BookReader("Mantra")); executor.execute(new BookReader("Karbla")); executor.execute(new BookReader("Sipahi")); System.out.println("Completed Task:"+ executor.getCompletedTaskCount()); System.out.println("Old Core Pool Size:"+ executor.getCorePoolSize()); executor.setCorePoolSize(3); System.out.println("New Core Pool Size:"+ executor.getCorePoolSize()); executor.shutdown(); } }
package com.concretepage; import java.util.concurrent.ThreadFactory; public class MyThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setPriority(Thread.MAX_PRIORITY ); System.out.println("---Thread Created---"); return t; } }
---Thread Created--- ---Thread Created--- Reading book: Mantra Reading book: Karbla Reading book: Mantra Reading book: Mantra Reading book: Karbla Reading book: Sipahi Reading book: Karbla Reading book: Sipahi Reading book: Sipahi Completed Task:2 Old Core Pool Size:2 New Core Pool Size:3
ThreadPoolExecutor
provides many adjustable parameters, we should prefer to use Executors.newCachedThreadPool()
, Executors.newFixedThreadPool(int)
and Executors.newSingleThreadExecutor()
over it.