线程池四种拒绝策略分析

线程池的定义主要实现在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还有很多值得挖掘的地方,笔者这里理解也有限,读者可以查阅代码,获得更细节的感悟。

你可能感兴趣的:(线程池四种拒绝策略分析)