The thread pool is used to manage the number of worker threads. It holds a queue of threads waiting for execution.
Java. util. Concurrent. executors provides the java. util. Concurrent. executor interface to create a thread pool in Java. Let's write a simple program to explain its working mechanism.
First, we need a runnable class.
Workerthread. Java
package com.journaldev.threadpool; public class WorkerThread implements Runnable { private String command; public WorkerThread(String s){ this.command=s; } @Override public void run() { System.out.println(Thread.currentThread().getName()+" Start. Command = "+command); processCommand(); System.out.println(Thread.currentThread().getName()+" End."); } private void processCommand() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public String toString(){ return this.command; }}
Here we use the executors framework to create a fixed thread pool test program.
Simplethreadpool. Java
package com.journaldev.threadpool; import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; public class SimpleThreadPool { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { Runnable worker = new WorkerThread("" + i); executor.execute(worker); } executor.shutdown(); // This will make the executor accept no new threads and finish all existing threads in the queue while (!executor.isTerminated()) { // Wait until all threads are finish,and also you can use "executor.awaitTermination();" to wait } System.out.println("Finished all threads"); } }
In the program, we create a thread pool with a fixed size of five working threads. Then allocate ten jobs to the thread pool. Because the thread pool size is five, it starts five worker threads to process five jobs first, and other jobs are in the waiting state, once a job is completed, the idle working thread will wait for other jobs in the queue for execution.
Here is the output of the above program.
Pool-1-thread-2 start. Command = 1
Pool-1-thread-4 start. Command = 3
Pool-1-thread-1 start. Command = 0
Pool-1-thread-3 Start. Command = 2
Pool-1-thread-5 start. Command = 4
Pool-1-thread-4 end.
Pool-1-thread-5 end.
Pool-1-thread-1 end.
Pool-1-thread-3 end.
Pool-1-thread-3 Start. Command = 8
Pool-1-thread-2 end.
Pool-1-thread-2 start. Command = 9
Pool-1-thread-1 start. Command = 7
Pool-1-thread-5 start. Command = 6
Pool-1-thread-4 start. Command = 5
Pool-1-thread-2 end.
Pool-1-thread-4 end.
Pool-1-thread-3 end.
Pool-1-thread-5 end.
Pool-1-thread-1 end.
Finished all threads
The output indicates that there are only five threads named "pool-1-thread-1" to "pool-1-thread-5" at the beginning and end of the thread pool, these five threads will not die with the completion of the work, and will always exist and be responsible for executing the tasks allocated to the thread pool until the thread pool disappears.
The executors class provides a simple executorservice implementation that uses threadpoolexecutor. However, threadpoolexecutor provides far more functions than this. We can specify the number of active threads when creating a threadpoolexecutor instance. We can also limit the thread pool size and create our own rejectedexecutionhandler implementation to handle jobs that cannot adapt to work queues.
Here is the implementation of our custom rejectedexecutionhandler interface.
Rejectedexecutionhandlerimpl. Java
package com.journaldev.threadpool; import java.util.concurrent.RejectedExecutionHandler;import java.util.concurrent.ThreadPoolExecutor; public class RejectedExecutionHandlerImpl implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.println(r.toString() + " is rejected"); } }
Threadpoolexecutor provides some methods. We can use these methods to query the current state, thread pool size, number of active threads, and number of tasks of executor. Therefore, I used a monitoring thread to print executor information at a specific time interval.
Mymonitorthread. Java
package com.journaldev.threadpool; import java.util.concurrent.ThreadPoolExecutor; public class MyMonitorThread implements Runnable{ private ThreadPoolExecutor executor; private int seconds; private boolean run=true; public MyMonitorThread(ThreadPoolExecutor executor, int delay) { this.executor = executor; this.seconds=delay; } public void shutdown(){ this.run=false; } @Override public void run() { while(run){ System.out.println( String.format("[monitor] [%d/%d] Active: %d, Completed: %d, Task: %d, isShutdown: %s, isTerminated: %s", this.executor.getPoolSize(), this.executor.getCorePoolSize(), this.executor.getActiveCount(), this.executor.getCompletedTaskCount(), this.executor.getTaskCount(), this.executor.isShutdown(), this.executor.isTerminated())); try { Thread.sleep(seconds*1000); } catch (InterruptedException e) { e.printStackTrace(); } } }}
Here is an example of threadpoolexecutor thread pool implementation.
Workerpool. Java
package com.journaldev.threadpool; import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.Executors;import java.util.concurrent.ThreadFactory;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit; public class WorkerPool { public static void main(String args[]) throws InterruptedException{ //RejectedExecutionHandler implementation RejectedExecutionHandlerImpl rejectionHandler = new RejectedExecutionHandlerImpl(); //Get the ThreadFactory implementation to use ThreadFactory threadFactory = Executors.defaultThreadFactory(); //creating the ThreadPoolExecutor ThreadPoolExecutor executorPool = new ThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), threadFactory, rejectionHandler); //start the monitoring thread MyMonitorThread monitor = new MyMonitorThread(executorPool, 3); Thread monitorThread = new Thread(monitor); monitorThread.start(); //submit work to the thread pool for(int i=0; i<10; i++){ executorPool.execute(new WorkerThread("cmd"+i)); } Thread.sleep(30000); //shut down the pool executorPool.shutdown(); //shut down the monitor thread Thread.sleep(5000); monitor.shutdown(); }}
Note that when initializing threadpoolexecutor, we keep the initial pool size to 2, the maximum pool size to 4, and the working queue size to 2. Therefore, if there are already four tasks in progress and more tasks are assigned at this time, the work queue will only keep two of them (new tasks), and the other will be processed by rejectedexecutionhandlerimpl.
The output of the above program can prove the above viewpoint.
Pool-1-thread-1 start. Command = defaults 0
Pool-1-thread-4 start. Command = limit 5
Limit 6 is rejected
Pool-1-thread-3 Start. Command = defaults 4
Pool-1-thread-2 start. Command = cmd1
Lifecycle 7 is rejected
Listen 8 is rejected
Reject 9 is rejected
[Monitor] [0/2] active: 4, completed: 0, task: 6, isshutdown:
False, isterminated: false
[Monitor] [4/2] active: 4, completed: 0, task: 6, isshutdown:
False, isterminated: false
Pool-1-thread-4 end.
Pool-1-thread-1 end.
Pool-1-thread-2 end.
Pool-1-thread-3 end.
Pool-1-thread-1 start. Command = cmd3
Pool-1-thread-4 start. Command = cmd2
[Monitor] [4/2] active: 2, completed: 4, task: 6, isshutdown:
False, isterminated: false
[Monitor] [4/2] active: 2, completed: 4, task: 6, isshutdown:
False, isterminated: false
Pool-1-thread-1 end.
Pool-1-thread-4 end.
[Monitor] [4/2] active: 0, completed: 6, task: 6, isshutdown:
False, isterminated: false
[Monitor] [2/2] active: 0, completed: 6, task: 6, isshutdown:
False, isterminated: false
[Monitor] [2/2] active: 0, completed: 6, task: 6, isshutdown:
False, isterminated: false
[Monitor] [2/2] active: 0, completed: 6, task: 6, isshutdown:
False, isterminated: false
[Monitor] [2/2] active: 0, completed: 6, task: 6, isshutdown:
False, isterminated: false
[Monitor] [2/2] active: 0, completed: 6, task: 6, isshutdown:
False, isterminated: false
[Monitor] [0/2] active: 0, completed: 6, task: 6, isshutdown:
True, isterminated: True
[Monitor] [0/2] active: 0, completed: 6, task: 6, isshutdown:
True, isterminated: True
Pay attention to the number of executor activity tasks, completed tasks, and all completed tasks. We can call the shutdown () method to end all submitted tasks and terminate the thread pool.
Link: http://www.journaldev.com/1069/java-thread-pool-example-using-executors-and-threadpoolexecutor