上篇博文《线程池源码解析》中,遗留了一个问题,拒绝策略。
这篇文章,大概说一下。
ThreadPoolExecutor
类中,线程池的拒绝策略有四种
- AbortPolicy 默认策略,丢弃任务,直接抛出异常。
- CallerRunsPolicy 由提交任务的线程,来执行任务。
- DiscardPolicy 丢弃任务,不抛异常,实际是啥也不做。
- DiscardOldestPolicy 将队列中老的任务丢弃,然后提交当前任务。
现在看下它们各自的源码
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) { // 1、工作线程数量小于核心线程数,创建线程
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) { // 2、将任务放入阻塞队列
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false)) // 3、队满时,继续创建线程,直至工作线程数量达到最大值。
reject(command); // 4、执行拒绝策略
}
先回顾下,线程池的运行,
- 工作线程数量小于核心线程数时,优先创建线程。
- 工作线程数量等于核心线程数时,将任务往阻塞队列中存在。
- 阻塞队列放不下时,继续创建工作线程,直到达到最大线程数。
- 以上三步还是处理不过来,执行拒绝策略。
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
这里的handle 是在创建线程池时,指定的一个参数。默认的拒绝策略是AbortPolicy
/**
* A handler for rejected tasks that throws a
* {@code RejectedExecutionException}.
*/
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
代码很明了,传入的任务,没有做任何处理,只是抛出一个异常。
- CallerRunsPolicy
/**
* A handler for rejected tasks that runs the rejected task
* directly in the calling thread of the {@code execute} method,
* unless the executor has been shut down, in which case the task
* is discarded.
*/
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
这个处理还是比较合理的,线程池处理不过来的时候,由哪个线程提交的任务,就由哪个线程来执行。
- DiscardPolicy
/**
* A handler for rejected tasks that silently discards the
* rejected task.
*/
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
这个方法处理,很是懒,什么也没做,只是个空方法。
- DiscardOldestPolicy
/**
* A handler for rejected tasks that discards the oldest unhandled
* request and then retries {@code execute}, unless the executor
* is shut down, in which case the task is discarded.
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll(); // 队头worker出队,给新任务腾个地方
e.execute(r); // 执行任务
}
}
}