In this journal entry, “Understanding Java Thread Pool”, we will be answering to the question “Why the application need a thread pool?”. Well the answer to this is when we develop a simple application in Java which needs some concurrent tasks to execute, we simply create Runnable
Thread
Related Journal Entries
Understanding Java Synchronized Keyword
Top 10 Java Collections Interview Questions and Answers
How to Monitor Disk, Memory, and Threads in Java?
Java Thread Pool
A thread pool is basically a collection of thread which
If the tasks execution is completed by anyone of the thread, then that thread can pickup a new task from the queue and start executing it. Once all the tasks are completed, threads remain active and a watcher keep watching queue for any new tasks. As soon as tasks come, threads again start picking up tasks and execute them.
ThreadPoolExecutor
Since Java 5, the Java concurrency API provides a mechanism Executor framework. Java Executor Framework (java.util.concurrent.Executor) is used to run the Runnable
objects without creating new threads every time and mostly re-using the already created threads. This works around ThreadPoolExecutor
class which implements the Executor
interface, its sub-interface ExecutorService
.
ThreadPoolExecutor
separates the task creation and its execution. ThreadPoolExecutor
Runnable
ThreadPoolExecutor
for their execution, instantiation, and running with necessary threads.
There are 5 different ways for creating a ThreadPoolExecutor:
#1 Fixed thread pool executor
Creates a thread pool with a fixed number of threads and reuses them to execute any number of tasks. When all the threads are active and if additional tasks are submitted, then they will have to wait in the queue until a thread is available. It is best fit for most off the real-life use-cases.
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
#2 Cached thread pool executor
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. DO NOT use this thread pool if tasks are long running. It can bring down the system if number of threads goes beyond what system can handle.
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
#3 Scheduled thread pool executor
Creates a thread pool that can schedule commands to run after a specified delay, or periodically.
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newScheduledThreadPool(10);
#4 Single thread pool executor
As the name suggests, it creates a single thread to execute all tasks. Use this only when you have one task to execute.
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newSingleThreadExecutor();
#5 Work stealing thread pool executor
In Java 8, a new type of thread pool is introduced as newWorkStealingPool() to complement the existing ones. Java gave a very succinct definition of this pool as:
“Creates a work-stealing thread pool using all available processors as its target parallelism level.”
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newWorkStealingPool(4);
ThreadPoolExecutor Example
Create class implementing Runnable Interface
Let’s create a class Message which will take random time to complete it, everytime.
package in.developersjournal.threadpool;
import java.util.concurrent.TimeUnit;
public class Message implements Runnable {
private String messageString;
public Message(String messageString) {
this.messageString = messageString;
}
public String getMessage() {
return messageString;
}
public void run() {
try {
Long duration = (long) (Math.random() * 10);
System.out.println("Message in Runnable: " + messageString);
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Create the main class with Thread Pool Executor
package in.developersjournal.threadpool;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class ThreadPoolExecutorExample
{
public static void main(String[] args)
{
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
for (int i = 1; i <= 10; i++)
{
Message message = new Message("Message: " + i);
System.out.println("Message Created : " + message.getMessage());
executor.execute(message);
}
executor.shutdown();
}
}
Output of the above code
Message Created : Message: 1
Message Created : Message: 2
Message Created : Message: 3
Message Created : Message: 4
Message Created : Message: 5
Message Created : Message: 6
Message Created : Message: 7
Message Created : Message: 8
Message Created : Message: 9
Message Created : Message: 10
Message in Runnable: Message: 3
Message in Runnable: Message: 4
Message in Runnable: Message: 5
Message in Runnable: Message: 1
Message in Runnable: Message: 2
Message in Runnable: Message: 6
Message in Runnable: Message: 8
Message in Runnable: Message: 7
Message in Runnable: Message: 10
Message in Runnable: Message: 9
Points to Remember
- Once you create
the ThreadPoolExecutor
class object you have to end it explicitly. If we forgot to end this, the executor will continue with the execution phase and the application or the program won’t end. We as developers have to make sure that our Java application ends smoothly because any Java application won’t end itself until all of its non-daemon threads finish their execution. So always remember to terminate the executor. - Use the shutdown() method of
the ThreadPoolExecutor
class , to indicate that the work is finished now. Once all the pending tasks are finished by the executor, then it finishes the execution. However, if you try to send another task to the executor once the shutdown() method has been called, the task will be rejected and the executor will throw a RejectedExecutionException exception. - A lot of methods are provided by the ThreadPoolExecutor class to get the information about its status:
#getPoolSize (): Information about the size of the pool
# getActiveCount(): Number of threads
# getCompletedTaskCount(): Number of completed tasks by the executor.
# getLargestPoolSize(): Maximum number of threads that have been in the pool at a time.
# shotdownNow(): Shutdowns the executor immediately. Stops the execution of all the pending tasks and returns a list of those tasks. However, the point to note here is that the tasks that are running continue with their execution, but the method doesn’t wait for their finalization.
#isTerminated (): This method returns true if you have called the shutdown() or shutdownNow() methods and the executor finishes the process of shutting it down.
# isShutdown(): This method returns true if you have called the shutdown() method of the executor.
#awaitTermination (long timeout, Time Unitunit): This method blocks the calling thread until the tasks of the executor have ended or the timeout occurs. The TimeUnit class is an enumeration with the following constants: DAYS, HOURS, MICROSECONDSetc .