线程池的定义主要实现在ThreadPoolExecutor,ThreadPoolExecutor提供的构造函数如下
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:
* {@code corePoolSize < 0}
* {@code keepAliveTime < 0}
* {@code maximumPoolSize <= 0}
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
corePoolSize线程池核心线程数量,maximumPoolSize线程池允许的最大线程数量,keepAliveTime空闲线程的存活时间,unit时间单位,workQueue等待队列,threadFactory线程工厂,handler拒绝处理器。RejectedExecutionHandler是一个接口,定义了线程池拒绝线程需要执行的方法。
public interface RejectedExecutionHandler {
/**
* Method that may be invoked by a {@link ThreadPoolExecutor} when
* {@link ThreadPoolExecutor#execute execute} cannot accept a
* task. This may occur when no more threads or queue slots are
* available because their bounds would be exceeded, or upon
* shutdown of the Executor.
* ...
* @param r the runnable task requested to be executed
* @param executor the executor attempting to execute this task
* @throws RejectedExecutionException if there is no remedy
*/
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
rejectedExecution方法则由不同的拒绝策略处理器去实现它的细节。
ThreadPoolExecutor中默认的拒绝策略是AbortPolicy
/**
* The default rejected execution handler
*/
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
AbortPolicy是ThreadPoolExecutor实现的一个内部类,查看实现的细节如下
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
该方法直接抛出拒绝异常。ThreadPoolExecutor还实现了另外三种线程拒绝处理器
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
oid rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
CallerRunsPolicy,顾名思义,就是调用者执行,指的是主线程提交一个任务给线程池,线程池很忙拒绝了,如果线程池采用的是此种策略,则交由主线程自己去完成。
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
DiscardPolicy,直接丢弃,不做任何处理
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
DiscardOldestPolicy,这种策略指的是丢弃等待队列里头节点的任务,执行刚提交的任务。
线程池拒绝的时机,我们可以看一下execute方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
其实这里注释讲的比较直白,代码逻辑处理也很清晰,主要分3步:1.如果线程池的工作线程小于设置的核心线程数,则调用addWorker增加一个工作线程,Worker为ThreadPoolExecutor定义的工作线程,继承于AbstractQueuedSynchronizer(implementing blocking locks);2.如果线程可以成功加入等待队列,则做一次double-check,即加入了队列后再次检查线程池运行状态,如果状态异常则从队列里删除,执行拒绝策略,否则如果判断没有工作线程了,则新加一个工作线程;3.如果等待队列已经满了,则尝试新加一个工作线程,如果失败执行拒绝策略。
这里简单从源码角度分析了线程池默认实现的四种拒绝策略,当然我们也可以通过实现RejectedExecutionHandler接口自定义拒绝策略处理器,然后在定义线程池的时候指定一下就可以了。ThreadPoolExecutor还有很多值得挖掘的地方,笔者这里理解也有限,读者可以查阅代码,获得更细节的感悟。