您的位置:首页 > 编程语言 > Java开发

Java Thread Pool Example using Executors and ThreadPoolExecutor

2013-11-20 00:00 701 查看
A thread pool manages the pool of worker threads, it contains a queue that keeps tasks waiting to get executed. 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.

01 package com.journaldev.threadpool;
02
03 public class WorkerThread implements Runnable {
04
05 private String command;
06
07 public WorkerThread(String s){
08 this.command=s;
09 }
10
11 @Override
12 public void run() {
13 System.out.println(Thread.currentThread().getName()+' Start. Command = '+command);
14 processCommand();
15 System.out.println(Thread.currentThread().getName()+' End.');
16 }
17
18 private void processCommand() {
19 try {
20 Thread.sleep(5000);
21 } catch (InterruptedException e) {
22 e.printStackTrace();
23 }
24 }
25
26 @Override
27 public String toString(){
28 return this.command;
29 }
30 }
Here is the test program where we are creating fixed thread pool from Executors framework.

01 package com.journaldev.threadpool;
02
03 import java.util.concurrent.ExecutorService;
04 import java.util.concurrent.Executors;
05
06 public class SimpleThreadPool {
07
08 public static void main(String[] args) {
09 ExecutorService executor = Executors.newFixedThreadPool(5);
10 for (int i = 0; i < 10; i++) {
11 Runnable worker = new WorkerThread('' + i);
12 executor.execute(worker);
13 }
14 executor.shutdown();
15 while (!executor.isTerminated()) {
16 }
17 System.out.println('Finished all threads');
18 }
19
20 }
In above program, we are creating fixed size thread pool of 5 worker threads. Then we are submitting 10 jobs to this pool, since the pool size is 5, it will start working on 5 jobs and other jobs will be in wait state, as soon as one of the job is finished, another job from the wait queue will be picked up by worker thread and get’s executed.
Here is the output of the above program.

01 pool-1-thread-2 Start. Command = 1
02 pool-1-thread-4 Start. Command = 3
03 pool-1-thread-1 Start. Command = 0
04 pool-1-thread-3 Start. Command = 2
05 pool-1-thread-5 Start. Command = 4
06 pool-1-thread-4 End.
07 pool-1-thread-5 End.
08 pool-1-thread-1 End.
09 pool-1-thread-3 End.
10 pool-1-thread-3 Start. Command = 8
11 pool-1-thread-2 End.
12 pool-1-thread-2 Start. Command = 9
13 pool-1-thread-1 Start. Command = 7
14 pool-1-thread-5 Start. Command = 6
15 pool-1-thread-4 Start. Command = 5
16 pool-1-thread-2 End.
17 pool-1-thread-4 End.
18 pool-1-thread-3 End.
19 pool-1-thread-5 End.
20 pool-1-thread-1 End.
21 Finished all threads
The output confirms that there are five threads in the pool named from “pool-1-thread-1? to “pool-1-thread-5? and they are responsible to execute the submitted tasks to the pool.
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.

01 package com.journaldev.threadpool;
02
03 import java.util.concurrent.RejectedExecutionHandler;
04 import java.util.concurrent.ThreadPoolExecutor;
05
06 public class RejectedExecutionHandlerImpl implements RejectedExecutionHandler {
07
08 @Override
09 public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
10 System.out.println(r.toString() + ' is rejected');
11 }
12
13 }
ThreadPoolExecutor provides several methods using which we can find out the current state of executor, pool size, active thread count and task count. So I have a monitor thread that will print the executor information at certain time interval.

01 package com.journaldev.threadpool;
02
03 import java.util.concurrent.ThreadPoolExecutor;
04
05 public class MyMonitorThread implements Runnable
06 {
07 private ThreadPoolExecutor executor;
08
09 private int seconds;
10
11 private boolean run=true;
12
13 public MyMonitorThread(ThreadPoolExecutor executor, int delay)
14 {
15 this.executor = executor;
16 this.seconds=delay;
17 }
18
19 public void shutdown(){
20 this.run=false;
21 }
22
23 @Override
24 public void run()
25 {
26 while(run){
27 System.out.println(
28 String.format('[monitor] [%d/%d] Active: %d, Completed: %d, Task: %d, isShutdown: %s, isTerminated: %s',
29 this.executor.getPoolSize(),
30 this.executor.getCorePoolSize(),
31 this.executor.getActiveCount(),
32 this.executor.getCompletedTaskCount(),
33 this.executor.getTaskCount(),
34 this.executor.isShutdown(),
35 this.executor.isTerminated()));
36 try {
37 Thread.sleep(seconds*1000);
38 } catch (InterruptedException e) {
39 e.printStackTrace();
40 }
41 }
42
43 }
44 }
Here is the thread pool implementation example using ThreadPoolExecutor.

01 package com.journaldev.threadpool;
02
03 import java.util.concurrent.ArrayBlockingQueue;
04 import java.util.concurrent.Executors;
05 import java.util.concurrent.ThreadFactory;
06 import java.util.concurrent.ThreadPoolExecutor;
07 import java.util.concurrent.TimeUnit;
08
09 public class WorkerPool {
10
11 public static void main(String args[]) throws InterruptedException{
12 //RejectedExecutionHandler implementation
13 RejectedExecutionHandlerImpl rejectionHandler = new RejectedExecutionHandlerImpl();
14 //Get the ThreadFactory implementation to use
15 ThreadFactory threadFactory = Executors.defaultThreadFactory();
16 //creating the ThreadPoolExecutor
17 ThreadPoolExecutor executorPool = new ThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS, newArrayBlockingQueue<Runnable>(2), threadFactory, rejectionHandler);
18 //start the monitoring thread
19 MyMonitorThread monitor = new MyMonitorThread(executorPool, 3);
20 Thread monitorThread = new Thread(monitor);
21 monitorThread.start();
22 //submit work to the thread pool
23 for(int i=0; i<10; i++){
24 executorPool.execute(new WorkerThread('cmd'+i));
25 }
26
27 Thread.sleep(30000);
28 //shut down the pool
29 executorPool.shutdown();
30 //shut down the monitor thread
31 Thread.sleep(5000);
32 monitor.shutdown();
33
34 }
35 }
Notice that while initializing the ThreadPoolExecutor, we are keeping initial pool size as 2, maximum pool size to 4 and work queue size as 2. So if there are 4 running tasks and more tasks are submitted, the work queue will hold only 2 of them and rest of them will be handled by RejectedExecutionHandlerImpl.
Here is the output of above program that confirms above statement.

01 pool-1-thread-1 Start. Command = cmd0
02 pool-1-thread-4 Start. Command = cmd5
03 cmd6 is rejected
04 pool-1-thread-3 Start. Command = cmd4
05 pool-1-thread-2 Start. Command = cmd1
06 cmd7 is rejected
07 cmd8 is rejected
08 cmd9 is rejected
09 [monitor] [0/2] Active: 4, Completed: 0, Task: 6, isShutdown: false, isTerminated: false
10 [monitor] [4/2] Active: 4, Completed: 0, Task: 6, isShutdown: false, isTerminated: false
11 pool-1-thread-4 End.
12 pool-1-thread-1 End.
13 pool-1-thread-2 End.
14 pool-1-thread-3 End.
15 pool-1-thread-1 Start. Command = cmd3
16 pool-1-thread-4 Start. Command = cmd2
17 [monitor] [4/2] Active: 2, Completed: 4, Task: 6, isShutdown: false, isTerminated: false
18 [monitor] [4/2] Active: 2, Completed: 4, Task: 6, isShutdown: false, isTerminated: false
19 pool-1-thread-1 End.
20 pool-1-thread-4 End.
21 [monitor] [4/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false
22 [monitor] [2/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false
23 [monitor] [2/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false
24 [monitor] [2/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false
25 [monitor] [2/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false
26 [monitor] [2/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false
27 [monitor] [0/2] Active: 0, Completed: 6, Task: 6, isShutdown: true, isTerminated: true
28 [monitor] [0/2] Active: 0, Completed: 6, Task: 6, isShutdown: true, isTerminated: true
Notice the change in active, completed and total completed task count of the executor. We can invoke shutdown() method to finish execution of all the submitted tasks and terminate the thread pool.

Reference: Java Thread Pool Example using Executors and ThreadPoolExecutor from our JCG partner Pankaj Kumar at the Developer Recipes blog.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: