ThreadPoll:线程池是我们使用中比较关注的东西,主要有4种,我们先看一下结构
该部分代码在dubbo-common里边 org.apache.dubbo.common.threadpool包,下面我们单个分析
1、CachedThreadPool:这个线程池是自动调优线程池,线程空闲一分钟后自动销毁,使用时再新建,看代码注释
public class CachedThreadPool implements ThreadPool {
/**
* 这个线程池是自调优线程池,1分钟后无使用者就清除,使用时再创建
* @param url URL contains thread parameter
* @return
*/
@Override
public Executor getExecutor(URL url) {
String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
//核心线程数,默认0
int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);
//最大线程数,默认Integer.MAX_VALUE
int threads = url.getParameter(THREADS_KEY, Integer.MAX_VALUE);
//阻塞队列数,默认0
int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
//线程空闲最大有效时间,默认60秒,超过时间销毁
int alive = url.getParameter(ALIVE_KEY, DEFAULT_ALIVE);
return new ThreadPoolExecutor(cores, threads, alive, TimeUnit.MILLISECONDS,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedInternalThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
2、EagerThreadPool:这个是当核心线程数用完后,直接创建线程,而不是放入阻塞队列
/**
* 当核心线程数用完后,创建新线程,而不是放入阻塞队列
* @param url URL contains thread parameter
* @return
*/
@Override
public Executor getExecutor(URL url) {
String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);
int threads = url.getParameter(THREADS_KEY, Integer.MAX_VALUE);
int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
int alive = url.getParameter(ALIVE_KEY, DEFAULT_ALIVE);
// init queue and executor
TaskQueue<Runnable> taskQueue = new TaskQueue<Runnable>(queues <= 0 ? 1 : queues);
EagerThreadPoolExecutor executor = new EagerThreadPoolExecutor(cores,
threads,
alive,
TimeUnit.MILLISECONDS,
taskQueue,
new NamedInternalThreadFactory(name, true),
new AbortPolicyWithReport(name, url));
taskQueue.setExecutor(executor);
return executor;
}
}
来看一下 EagerThreadPoolExecutor
public class EagerThreadPoolExecutor extends ThreadPoolExecutor {
/**
* task count
*/
private final AtomicInteger submittedTaskCount = new AtomicInteger(0);
public EagerThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit, TaskQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
/**
* @return current tasks which are executed
*/
public int getSubmittedTaskCount() {
return submittedTaskCount.get();
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
submittedTaskCount.decrementAndGet();
}
@Override
public void execute(Runnable command) {
if (command == null) {
throw new NullPointerException();
}
// do not increment in method beforeExecute!
submittedTaskCount.incrementAndGet();
try {
super.execute(command);
} catch (RejectedExecutionException rx) {
// retry to offer the task into queue.
final TaskQueue queue = (TaskQueue) super.getQueue();
try {
//将任务提交到队列中
if (!queue.retryOffer(command, 0, TimeUnit.MILLISECONDS)) {
submittedTaskCount.decrementAndGet();
throw new RejectedExecutionException("Queue capacity is full.", rx);
}
} catch (InterruptedException x) {
submittedTaskCount.decrementAndGet();
throw new RejectedExecutionException(x);
}
} catch (Throwable t) {
// decrease any way
submittedTaskCount.decrementAndGet();
throw t;
}
}
}
主要重写了execute ,如果触发拒绝策略,将任务提交到队列中,再看TaskQueue
public class TaskQueue<R extends Runnable> extends LinkedBlockingQueue<Runnable> {
private static final long serialVersionUID = -2635853580887179627L;
private EagerThreadPoolExecutor executor;
public TaskQueue(int capacity) {
super(capacity);
}
public void setExecutor(EagerThreadPoolExecutor exec) {
executor = exec;
}
@Override
public boolean offer(Runnable runnable) {
if (executor == null) {
throw new RejectedExecutionException("The task queue does not have executor!");
}
int currentPoolThreadSize = executor.getPoolSize();
// have free worker. put task into queue to let the worker deal with task.
//如果提交任务数小于当前工作线程数,说明当前工作线程足够处理任务,将提交的任务插入到工作队列
if (executor.getSubmittedTaskCount() < currentPoolThreadSize) {
return super.offer(runnable);
}
// return false to let executor create new worker.
//如果提交任务数大于当前工作线程数并且小于最大线程数,说明提交的任务量线程已经处理不过来,那么需要增加线程数,返回false
if (currentPoolThreadSize < executor.getMaximumPoolSize()) {
return false;
}
// currentPoolThreadSize >= max
//工作线程数到达最大线程数,插入到workqueue
return super.offer(runnable);
}
/**
* retry offer task
*
* @param o task
* @return offer success or not
* @throws RejectedExecutionException if executor is terminated.
*/
public boolean retryOffer(Runnable o, long timeout, TimeUnit unit) throws InterruptedException {
if (executor.isShutdown()) {
throw new RejectedExecutionException("Executor is shutdown!");
}
return super.offer(o, timeout, unit);
}
}
主要重写了offer方法,retryOffer调用offer,看代码注释、、、
3、FixedThreadPool:固定线程数线程池,核心和最大线程数默认都是200,看注释
public class FixedThreadPool implements ThreadPool {
/**
* 固定线程数线程池
* @param url URL contains thread parameter
* @return
*/
@Override
public Executor getExecutor(URL url) {
String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
//线程数,默认200
int threads = url.getParameter(THREADS_KEY, DEFAULT_THREADS);
//最大阻塞队列,默认0:代表无限阻塞队列
int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
return new ThreadPoolExecutor(threads, threads, 0, TimeUnit.MILLISECONDS,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedInternalThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
4、 LimitedThreadPool:这个线程池会一直创建线程,并且线程不会销毁,目的防止突发流量,但过了高峰期后会浪费资源,主要体现在keepAliveTime=Long.MAX_VALUE
public class LimitedThreadPool implements ThreadPool {
/**
* 只会一直创建线程,永远不会销毁,目的防止突发流量,但流量低谷时会浪费资源
* @param url URL contains thread parameter
* @return
*/
@Override
public Executor getExecutor(URL url) {
String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);
int threads = url.getParameter(THREADS_KEY, DEFAULT_THREADS);
int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
return new ThreadPoolExecutor(cores, threads, Long.MAX_VALUE, TimeUnit.MILLISECONDS,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedInternalThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
总结:dubbo缺省FixedThreadPool线程池
公众号主要记录各种源码、面试题、微服务技术栈,帮忙关注一波,非常感谢