ThreadPoolExecutor – Java Thread Pool Example(如何使用Executor框架创建一个线程池)
Java thread pool manages the pool of worker threads, it contains a queue that keeps tasks waiting to get executed. We can use ThreadPoolExecutor
to create thread pool in java.
Java 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, named WorkerThread.java
package com.joualdev.threadpool;public class WorkerThread implements Runnable {
<span class="hljs-keyword">private</span> String command;<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WorkerThread</span><span class="hljs-params">(String s)</span></span>{<span class="hljs-keyword">this</span>.command=s;}<span class="hljs-meta">@Override</span><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{System.out.println(Thread.currentThread().getName()+<span class="hljs-string">" Start. Command = "</span>+command);processCommand();System.out.println(Thread.currentThread().getName()+<span class="hljs-string">" End."</span>);}<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processCommand</span><span class="hljs-params">()</span> </span>{<span class="hljs-keyword">try</span> {Thread.sleep(<span class="hljs-number">5000</span>);} <span class="hljs-keyword">catch</span> (InterruptedException e) {e.printStackTrace();}}<span class="hljs-meta">@Override</span><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span></span>{<span class="hljs-keyword">retu</span> <span class="hljs-keyword">this</span>.command;}
}
ExecutorService Example
Here is the test program class SimpleThreadPool.java
, where we are creating fixed thread pool from Executors framework.
Copypackage com.joualdev.threadpool;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SimpleThreadPool {
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{ExecutorService executor = Executors.newFixedThreadPool(<span class="hljs-number">5</span>);<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">10</span>; i++) {Runnable worker = <span class="hljs-keyword">new</span> WorkerThread(<span class="hljs-string">""</span> + i);executor.execute(worker); }executor.shutdown();<span class="hljs-keyword">while</span> (!executor.isTerminated()) {}System.out.println(<span class="hljs-string">"Finished all threads"</span>);}
}
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.
Copypool-1-thread-2 Start. Command = 1pool-1-thread-4 Start. Command = 3pool-1-thread-1 Start. Command = 0pool-1-thread-3 Start. Command = 2pool-1-thread-5 Start. Command = 4pool-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 = 8pool-1-thread-2 End.pool-1-thread-2 Start. Command = 9pool-1-thread-1 Start. Command = 7pool-1-thread-5 Start. Command = 6pool-1-thread-4 Start. Command = 5pool-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 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.
ThreadPoolExecutor Example
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.
Copypackage com.joualdev.threadpool;import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
public class RejectedExecutionHandlerImpl implements RejectedExecutionHandler {
<span class="hljs-meta">@Override</span><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">rejectedExecution</span><span class="hljs-params">(Runnable r, ThreadPoolExecutor executor)</span> </span>{System.out.println(r.toString() + <span class="hljs-string">" is rejected"</span>);}
}
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.
Copypackage com.joualdev.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;}@Overridepublic 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 the thread pool implementation example using ThreadPoolExecutor.
Copypackage com.joualdev.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 {
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String args[])</span> <span class="hljs-keyword">throws</span> InterruptedException</span>{<span class="hljs-comment">//RejectedExecutionHandler implementation</span>RejectedExecutionHandlerImpl rejectionHandler = <span class="hljs-keyword">new</span> RejectedExecutionHandlerImpl();<span class="hljs-comment">//Get the ThreadFactory implementation to use</span>ThreadFactory threadFactory = Executors.defaultThreadFactory();<span class="hljs-comment">//creating the ThreadPoolExecutor</span>ThreadPoolExecutor executorPool = <span class="hljs-keyword">new</span> ThreadPoolExecutor(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>, <span class="hljs-number">10</span>, TimeUnit.SECONDS, <span class="hljs-keyword">new</span> ArrayBlockingQueue<Runnable>(<span class="hljs-number">2</span>), threadFactory, rejectionHandler);<span class="hljs-comment">//start the monitoring thread</span>MyMonitorThread monitor = <span class="hljs-keyword">new</span> MyMonitorThread(executorPool, <span class="hljs-number">3</span>);Thread monitorThread = <span class="hljs-keyword">new</span> Thread(monitor);monitorThread.start();<span class="hljs-comment">//submit work to the thread pool</span><span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i<<span class="hljs-number">10</span>; i++){executorPool.execute(<span class="hljs-keyword">new</span> WorkerThread(<span class="hljs-string">"cmd"</span>+i));}Thread.sleep(<span class="hljs-number">30000</span>);<span class="hljs-comment">//shut down the pool</span>executorPool.shutdown();<span class="hljs-comment">//shut down the monitor thread</span>Thread.sleep(<span class="hljs-number">5000</span>);monitor.shutdown();}
}
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.
Copypool-1-thread-1 Start. Command = cmd0pool-1-thread-4 Start. Command = cmd5cmd6 is rejectedpool-1-thread-3 Start. Command = cmd4pool-1-thread-2 Start. Command = cmd1cmd7 is rejectedcmd8 is rejectedcmd9 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: falsepool-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 = cmd3pool-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: falsepool-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
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.
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.
作者:星朝
来源链接:https://www.cnblogs.com/jpfss/p/9373282.html
版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。
2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。