引子问题
问题1:什么时候触发拒绝策略?
问题2:拒绝策略有哪些?
问题3:默认的拒绝策略是什么?
问题4:你实际开发经历中的拒绝策略是什么?
创建线程池
核心线程数、最大线程数、空闲存活时间根据业务决定
任务队列避免使用无界队列,以免产生OOM
int coreSize = 4;
int maximumPoolSize = 8;
long keepAliveTime = 5;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(20);
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
ThreadPoolExecutor pool = new ThreadPoolExecutor(coreSize,maximumPoolSize,keepAliveTime,unit,workQueue,handler);
拒绝策略有哪些
严格来说,只要实现了RejectedExecutionHandler接口的,都可以作为拒绝策略,这里讨论的是JUC自带的拒绝策略。
上源码……
package java.util.concurrent;
/**
* A handler for tasks that cannot be executed by a {@link ThreadPoolExecutor}.
*
* @since 1.5
* @author Doug Lea
*/
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.
*
* <p>In the absence of other alternatives, the method may throw
* an unchecked {@link RejectedExecutionException}, which will be
* propagated to the caller of {@code execute}.
*
* @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);
}
上源码显示,JUC自带的拒绝策略有四个
AbortPolicy
抛出异常RejectedExecutionException
/**
* 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());
}
}
AbortPolicy是JUC的默认拒绝策略
/**
* The default rejected execution handler
*/
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
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();
}
}
}
DiscardOldestPolicy
喜新厌旧,将任务队列中最久未处理(oldest unhandled)的任务丢弃,然后尝试执行当前任务,如果线程池关闭了,这个任务也将被丢弃
/**
* 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();
e.execute(r);
}
}
}
DiscardPilicy
佛系拒绝,什么也不做
/**
* 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) {
}
}
揭晓答案
什么时候触发拒绝策略?
一图胜千言
拒绝策略有哪些?
默认的拒绝策略是什么?
你实际开发经历中的拒绝策略是什么?
分场景:看实际场景中任务重要性,如果是不重要的任务,默认的拒绝策略就好了,佛系,无为而治,什么也不做
如果任务很重要,不能丢,看了上面的四种拒绝策略,业务不允许丢弃任务的场景里,都不靠谱,就需要重写RejectedExecutionHandler接口自定义拒绝策略
比如当发生拒绝时将任务转发到MQ中,稍后再处理
另外多提一句,这里就是23中设计模式中——策略模式,使用的是一个典型场景,面试八股文奇怪的知识又增加了!