0 文章概述
动态线程池是指可以动态调节线程池某些参数,本文我们结合Apollo和线程池实现一个动态线程池。
1 线程池基础
1.1 七个参数
我们首先回顾Java线程池七大参数,这对后续设置线程池参数有帮助。我们查看ThreadPoolExecutor构造函数如下:
public class ThreadPoolExecutor extends AbstractExecutorService {
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
}
corePoolSize
线程池核心线程数,类比业务大厅开设的固定窗口。例如业务大厅开设2个固定窗口,那么这两个窗口不会关闭,全天都会进行业务办理
workQueue
存储已提交但尚未执行的任务,类比业务大厅等候区。例如业务大厅一开门进来很多顾客,2个固定窗口进行业务办理,其他顾客到等候区等待
maximumPoolSize
线程池可以容纳同时执行最大线程数,类比业务大厅最大窗口数。例如业务大厅最大窗口数是5个,业务员看到2个固定窗口和等候区都满了,可以临时增加3个窗口
keepAliveTime
非核心线程数存活时间。当业务不忙时刚才新增的3个窗口需要关闭,空闲时间超过keepAliveTime空闲会被关闭
unit
keepAliveTime存活时间单位
threadFactory
线程工厂可以用来指定线程名
handler
线程池线程数已达到maximumPoolSize且队列已满时执行拒绝策略。例如业务大厅5个窗口全部处于忙碌状态且等候区已满,业务员根据实际情况选择拒绝策略
1.2 四种拒绝策略
(1) AbortPolicy
默认策略直接抛出RejectExecutionException阻止系统正常运行
/**
* AbortPolicy
*
* @author
*
*/
public class AbortPolicyTest {
public static void main(String[] args) {
int coreSize = 1;
int maxSize = 2;
int queueSize = 1;
AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy();
ThreadPoolExecutor executor = new ThreadPoolExecutor(coreSize, maxSize, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(queueSize), Executors.defaultThreadFactory(), abortPolicy);
for (int i = 0; i < 100; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " -> run");
}
});
}
}
}
程序执行结果:
pool-1-thread-1 -> run
pool-1-thread-2 -> run
pool-1-thread-1 -> run
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.xy.juc.threadpool.reject.AbortPolicyTest$1@70dea4e rejected from java.util.concurrent.ThreadPoolExecutor@5c647e05[Running, pool size = 2, active threads = 0, queued tasks = 0, completed tasks = 2]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at com.xy.juc.threadpool.reject.AbortPolicyTest.main(AbortPolicyTest.java:21)
(2) CallerRunsPolicy
任务回退给调用者自己运行
/**
* CallerRunsPolicy
*
* @author
*
*/
public class CallerRunsPolicyTest {
public static void main(String[] args) {
int coreSize = 1;
int maxSize = 2;
int queueSize = 1;
CallerRunsPolicy callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();