A thread pool manages the collection of Runnable threads and worker threads execute Runnable from the queue.
java.util.concurrent.Executors provide implementation of java.util.concurrent.Executor interface to create the thread pool in java. Let’s write a simple program to explain it’s working.
First we need to have a Runnable class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| 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; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| 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(); while (!executor.isTerminated()) { } System.out.println( "Finished all threads" ); } } |
Here is the output of the above program.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| 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 |
Executors class provide simple implementation of ExecutorService using ThreadPoolExecutor but ThreadPoolExecutor provides much more feature than that. We can specify the number of threads that will be alive when we create ThreadPoolExecutor instance and we can limit the size of thread pool and create our own RejectedExecutionHandler implementation to handle the jobs that can’t fit in the worker queue.
Here is our custom implementation of RejectedExecutionHandler interface.
1
2
3
4
5
6
7
8
9
10
11
12
13
| 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" ); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| 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(); } } } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| 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(); } } |
Here is the output of above program that confirms above statement.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| pool-1-thread-1 Start. Command = cmd0 pool-1-thread-4 Start. Command = cmd5 cmd6 is rejected pool-1-thread-3 Start. Command = cmd4 pool-1-thread-2 Start. Command = cmd1 cmd7 is rejected cmd8 is rejected cmd9 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 |
If you want to schedule a task to run with delay or periodically then you can use ScheduledThreadPoolExecutor class. Read more about them at Java Schedule Thread Pool Executor.
Source: Internet