Executor(三):ThreadPoolExecutor源码解析 jdk1.8

目录

ThreadPoolExecutor成员变量介绍

主要方法

内部运行原理


 为什么要使用ThreadPoolExecutore,使用它能解决什么问题?

在jdk文档中给出了说明。

Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, including threads, consumed when executing a collection of tasks. Each ThreadPoolExecutor also maintains some basic statistics, such as the number of completed tasks.

线程池解决两个不同的问题:他们通常提供改进性能当执行大量的异步任务时。为了减少每个任务的调用开销。并且他们提供一个边界手段和管理资源。包括线程,在执行一个集合任务的消耗。每个ThreadPoolExecutor也保持一些基本统计,比如完成任务的数量。

可以看到线程池相比单独使用线程可以减少线程频繁创建和销毁所产生的开销,并且它能使用一定的规则控制线程的数量,从而避免计算机资源耗尽。同时,它也能提供一些统计等,方便进行异步任务的耗时,日志等统计。

但是如果不懂线程池的内部原理还容易乱用,用错。所以在阿里的规范手册中建议自己手动构建线程池不要使用JDK提供的工厂类Executors中提供的几种设定好的线程池。

ThreadPoolExecutor成员变量介绍

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
//这里减去1的目的是使CAPACITY的二进制变为全1的形式,方便分离ctl中的运行状态和当前的工作线程数
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;

// Packing and unpacking ctl
private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c)  { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }

这里最重要的就是ctl字段,它包含了线程池的工作状态和线程池当前的工作线程数。高位表示线程池状态低位表示线程池中运行的线程数。通过runStateOf获取线程状态,workerCountOf获取工作线程数。

In order to pack them into one int, we limit workerCount to(2^29)-1 (about 500 million) threads rather than (2^31)-1 (2billion) otherwise representable. If this is ever an issue inthe future, the variable can be changed to be an AtomicLong,and the shift/mask constants below adjusted. But until the need arises, this code is a bit faster and simpler using an int. 

为了将他们放到一个int变量中。我限制工作线程(2^29)-1大概500百万线程 而不是(2^31)-1.如果这在将来成为一个问题,变量可以改变成为Long类型的原子变量 shift/mask常量也要做调整。但是直到需要发生,这个代码使用int是会快一点和简单

The workerCount is the number of workers that have been permitted to start and not
permitted to stop.  The value may be transiently different from the actual number of live
threads, for example when a ThreadFactory fails to create a thread when asked, and when exiting threads are still 
performing bookkeeping before terminating. The user-visible
pool size is reported as the current size of the workers set.
工作线程数是工作的已经允许运行并且不允许停止的线程数。这个值可能短暂的不同于真实的活跃的线程数。比
如:当一个线程工厂创建一个线程失败当需要的时候还有当存在线程仍然在执行终止前的记账。线程池大小使用
者可见性是返回当前工作线程集合的大小。

线程池状态介绍
RUNNING:  Accept new tasks and process queued tasks
运行时:接受一个新的任务并且处理队列任务。

SHUTDOWN: Don't accept new tasks, but process queued tasks
关闭:不接收新的任务,但是处理队列中的任务

STOP: Don't accept new tasks, don't process queued tasks, and interrupt in-progress tasks
停止:不接受新的任务,不处理队列任务,并且中断正在处理的任务

TIDYING:  All tasks have terminated, workerCount is zero,the thread transitioning to state TIDYING
will run the terminated() hook method
收拾:所有任务都终止,工作线程为0,线程过度到TIDYING状态将会运行terminated钩子方法

TERMINATED: terminated() has completed
终止:terminated()方法已经执行完毕

状态之间的转换

  The queue used for holding tasks and handing off to workerthreads.  We do not require 
that workQueue.poll() returningnull necessarily means that workQueue.isEmpty(), so 
relysolely on isEmpty to see if the queue is empty (which we mustdo for example when 
deciding whether to transition fromSHUTDOWN to TIDYING).  This accommodates special-
purposequeues such as DelayQueues for which poll() is allowed to return null even if it may 
later return non-null when delays expire.
 队列被用来保存任务并且传递给工作线程,我们不要求poll方法返回null必然意味着工作队列是空的,因此唯一
依赖isEmpty方法去判断对垒是否为空(我们必须举例,比如,当决定是否要将SHUTDOWN状态转换为TIDYING)这
样一来专门队列比如DelayQueues的poll方法允许返回null自己它可能晚点返回非空的当延期期满
private final BlockingQueue<Runnable> workQueue;


Lock held on access to workers set and related bookkeeping. While we could use a concurrent set of some sort, it turns out  to be generally preferable to use a lock. Among the reasons is  that this serializes interruptIdleWorkers, which avoids unnecessary interrupt storms, especially during shutdown. Otherwise exiting threads would concurrently interrupt those that have not yet interrupted. It also simplifies some of the associated statistics bookkeeping of largestPoolSize etc. We  also hold mainLock on shutdown and shutdownNow, for the sake of ensuring workers set is stable while separately checking permission to interrupt and actually interrupting.
锁用于访问工作者集合和关联记录。当我们使用某种并发集合,事实证明最好使用锁。其中的一个原因是序列化interruptIdleWorkers,避免中断风暴,特别是在关闭的时候。否则,退出线程那些还没有中断的将同时中断。它也简化了最大线程数关联统计记录等等。我们也次有mainLock在shutdown和shutdownNow方法。为了确保工作线程集合时稳定的在分别检查允许中断和真实中断中的期间
 private final ReentrantLock mainLock = new ReentrantLock();

Set containing all worker threads in pool. Accessed only when holding mainLock.
 集合包含线程池所有工作线程。存取只有在持有mainLock的时候
 private final HashSet<Worker> workers = new HashSet<Worker>();


Factory for new threads. All threads are created using this factory (via method addWorker).  All callers must be prepared  for addWorker to fail, which may reflect a system or user's policy limiting the number of threads.  Even though it is not treated as an error, failure to create threads may result in new tasks being rejected or existing ones remaining stuck in the queue.
工厂用用创建新的线程。所有线程被创建使用这个工厂。经由方法addWorker.  所有的调用者必须准备addWorker失败的情况,可能反应一个系统或用户的策略限制线程的数量。及时它不是作为一个错误对待,创建一个线程失败可能导致一个新的任务被拒绝或先行在队列中的任务卡死
private volatile ThreadFactory threadFactory;

 Handler called when saturated or shutdown in execute.
 在调用时出现饱和和关闭的应对方法
 private volatile RejectedExecutionHandler handler;

Core pool size is the minimum number of workers to keep alive (and not allow to time out etc) unless allowCoreThreadTimeOut is set, in which case the minimum is zero.

核心线程池大小,除非设置了允许核心线程,那种情况下这个值允许为0

private volatile int corePoolSize;

Maximum pool size. Note that the actual maximum is internally bounded by CAPACITY. 

允许最大的线程数

private volatile int maximumPoolSize;

 

工作类

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */
        private static final long serialVersionUID = 6138294804551838833L;

        /** Thread this worker is running in.  Null if factory fails. */
        //工作线程
        final Thread thread;
        /** Initial task to run.  Possibly null. */
        //执行的第一个任务
        Runnable firstTask;
        /** Per-thread task counter */
        //当前线程线程执行的任务数
        volatile long completedTasks;

        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
            runWorker(this);
        }

        // Lock methods
        //
        // The value 0 represents the unlocked state.
        // The value 1 represents the locked state.
        //使用AQS构建锁
        protected boolean isHeldExclusively() {
            return getState() != 0;
        }

        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }

        //中断线程
        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }

主要方法

尝试终止线程池方法

 /**
     * Transitions to TERMINATED state if either (SHUTDOWN and pool
     * and queue empty) or (STOP and pool empty).  If otherwise
     * eligible to terminate but workerCount is nonzero, interrupts an
     * idle worker to ensure that shutdown signals propagate. This
     * method must be called following any action that might make
     * termination possible -- reducing worker count or removing tasks
     * from the queue during shutdown. The method is non-private to
     * allow access from ScheduledThreadPoolExecutor.
     * 转换去TERMINATED状态如果(SHUTDOWN并且线程池和队列都是空的)或者
     * (STOP且线程池是空的)满足一个。如果其他的满足条件但是工作线程不是0,
     * 中断一个空闲工作线程去确保关闭信号传播。这个方法必须被调用跟随任何行为
     * ,可能产生终止的行为。
     */
    final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            //如果线程池还是运行状态或运行状态大于TIDYING或者(运行状态是关闭的且工作队列不为空
            //满足上面中的一种都将会直接返回,
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            //如果到这里说明工作状态是SHUTDOWN或STOP,且如果是SHUTDOWN工作队列也必须为空
            //如果工作线程不为空,则会中断一个线程
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                //设置为TIDYING状态,工作线程设置为0
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

关闭线程池方法shutdown和shutdownNow对比 

/**
     * Initiates an orderly shutdown in which previously submitted
     * tasks are executed, but no new tasks will be accepted.
     * Invocation has no additional effect if already shut down.
     * 开启一个有序的关闭,先提交的任务会被执行,但是新的任务提交不会被接受。
     * <p>This method does not wait for previously submitted tasks to
     * complete execution.  Use {@link #awaitTermination awaitTermination}
     * to do that.
     * 这个方法不会等到先前提交的任务执行完毕,如果想这样使用awaitTermination方法。
     *
     * @throws SecurityException {@inheritDoc}
     */
    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            //设置线程池状态
            advanceRunState(SHUTDOWN);
            //中断线程,但是要获取到worker的锁
            interruptIdleWorkers();
            //执行正在关闭的钩子方法
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        //尝试去转换terminate状态
        tryTerminate();
    }
/**
     * Attempts to stop all actively executing tasks, halts the
     * processing of waiting tasks, and returns a list of the tasks
     * that were awaiting execution. These tasks are drained (removed)
     * from the task queue upon return from this method.
     * 企图去停止所有活跃在执行的任务,停止正在等待任务的处理,并且返回一个
     * 那些等待执行的任务。这个方法返回的任务都是从工作队列中移除的。
     * <p>This method does not wait for actively executing tasks to
     * terminate.  Use {@link #awaitTermination awaitTermination} to
     * do that.
     * 这个方法不会等待正在执行的任务停止,
     *
     * <p>There are no guarantees beyond best-effort attempts to stop
     * processing actively executing tasks.  This implementation
     * cancels tasks via {@link Thread#interrupt}, so any task that
     * fails to respond to interrupts may never terminate.
     * 这个不保证超过最大努力去通知正在执行的任务。这个实现取消任务通过中断完成
     * 因此任务任务对中断回应失败可能永远都不会终止
     *
     * @throws SecurityException {@inheritDoc}
     */
    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(STOP);
            //直接中断所有线程
            interruptWorkers();
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

可以看到shutdown()和shutdownNow()方法大致一致,但是还是有几个地方有区别,一个是设置线程池的状态,还有一个是调用线程中断的方法。

shutdown调用的方法interruptIdleWorkers

/**
     * Common form of interruptIdleWorkers, to avoid having to
     * remember what the boolean argument means.
     */
    private void interruptIdleWorkers() {
        interruptIdleWorkers(false);
    }
/**
     * Interrupts threads that might be waiting for tasks (as
     * indicated by not being locked) so they can check for
     * termination or configuration changes. Ignores
     * SecurityExceptions (in which case some threads may remain
     * uninterrupted).
     * 中断那些可能在等待任务的线程(表明没有被锁)隐藏他们能被
     * 检测终止或设置改变。忽略SecurityExceptions在这种情况一些线程可能保持
     * 不中断
     *
     * @param onlyOne If true, interrupt at most one worker. This is
     * called only from tryTerminate when termination is otherwise
     * enabled but there are still other workers.  In this case, at
     * most one waiting worker is interrupted to propagate shutdown
     * signals in case all threads are currently waiting.
     * Interrupting any arbitrary thread ensures that newly arriving
     * workers since shutdown began will also eventually exit.
     * To guarantee eventual termination, it suffices to always
     * interrupt only one idle worker, but shutdown() interrupts all
     * idle workers so that redundant workers exit promptly, not
     * waiting for a straggler task to finish.
     *                如果onlyOne为true,最多会中断一个工作线程。这是只有在
     *                tryTerminate方法中会这样调用当终止时其他启动但是仍然有其他工作线程
     *                在这种情况,最多一个等待的工作此案城被中断去传播关闭信号如果所有线程都在等待。
     *                中断任何任意线程确保新到达工作线程自关闭开始也最终离开。
     *                去保证最终终止,它通常足够中断只有一个空闲线程,但是shutdown方法中断
     *                所有空闲线程隐藏过剩的工作离开,不要等待一个流浪的任务去完成。
     */
    private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }

shutdownNow()调用的中断方法

/**
     * Interrupts all threads, even if active. Ignores SecurityExceptions
     * (in which case some threads may remain uninterrupted).
     * 中断所有线程,即使是活跃的。忽略安全异常。这种情况一些线程可能保持不中断。
     * 这里的不需要或者工作类的锁,但是shutdown中的方法需要获取worker的锁
     */
    private void interruptWorkers() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers)
                w.interruptIfStarted();
        } finally {
            mainLock.unlock();
        }
    }
void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }

大致上也是差不多的,区别在于shutdownNow调用的中断方法不用去获取worker的锁,也就是可以任意的中断线程,但是shutdown调用的需要去获取worker的锁。这点区别造成的影响就是shutdown不可能中断正在运行任务的线程,因为锁被正在运行任务的方法获取了。需要等到方法执行完再去竞争锁。但是shutdownNow是可以直接中断重在运行任务的线程,前提是那个任务会响应中断。

添加工作线程方法

/**
     * Checks if a new worker can be added with respect to current
     * pool state and the given bound (either core or maximum). If so,
     * the worker count is adjusted accordingly, and, if possible, a
     * new worker is created and started, running firstTask as its
     * first task. This method returns false if the pool is stopped or
     * eligible to shut down. It also returns false if the thread
     * factory fails to create a thread when asked.  If the thread
     * creation fails, either due to the thread factory returning
     * null, or due to an exception (typically OutOfMemoryError in
     * Thread.start()), we roll back cleanly.
     * 检测一个新的工程线程能被添加关于当前线程池状态和给定的核心线程数和最大线程数
     * 如果是这样的话,工作线程数会被相应的调整,如果可能,一个新的工作线程被创建和开始
     * 运行firstTask参数做为他的第一个任务。这个方法返回false如果线程池是停止的
     * 或者被关闭。如果线程工厂创建线程失败也会返回false.
     * @param firstTask the task the new thread should run first (or
     * null if none). Workers are created with an initial first task
     * (in method execute()) to bypass queuing when there are fewer
     * than corePoolSize threads (in which case we always start one),
     * or when the queue is full (in which case we must bypass queue).
     * Initially idle threads are usually created via
     * prestartCoreThread or to replace other dying workers.
     *
     * @param core if true use corePoolSize as bound, else
     * maximumPoolSize. (A boolean indicator is used here rather than a
     * value to ensure reads of fresh values after checking other pool
     * state).
     * @return true if successful
     */
    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //如果运行状态大于等于SHUTDOWN且 不满足 (运行状态是SHUTDOWN且任务参数为空且工作队列不为空)=》也就是如果是SHUTDOWN状态下还有任务没有完成
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                //当前工作线程数
                int wc = workerCountOf(c);
                //如果当前线程数超过了最大线程数或超过了当前设定对应类型工作线程的数量
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //如果这里工作线程数加一成功,但是后面的创建线程失败了,会在addWorkerFailed方法中将这个数减一
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                //如果ctl发生改变,则重新开始。
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                            //这里这样判断是如果是SHTUDOWN状态就不会接受新任务了
                        (rs == SHUTDOWN && firstTask == null)) {
                        //检测线程是否开始运行。
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    //如果创建成功则启动线程
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                //如果创建线程失败则回滚。
                addWorkerFailed(w);
        }
        return workerStarted;
    }
/**
     * Rolls back the worker thread creation.
     * - removes worker from workers, if present
     * - decrements worker count
     * - rechecks for termination, in case the existence of this
     *   worker was holding up termination
     *
     *   回滚工作线程的创建。
     *   --移除工作线程从工作集合中,如果已经存在
     *   --减少工作线程数
     *   --再次检查是否终止,
     */
    private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (w != null)
                workers.remove(w);
            decrementWorkerCount();
            tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }

运行任务

/**
     * Main worker run loop.  Repeatedly gets tasks from queue and
     * executes them, while coping with a number of issues:
     * 主要工作循环。反复过去任务从队列并且执行他们,在处理一些问题时
     *
     * 1. We may start out with an initial task, in which case we
     * don't need to get the first one. Otherwise, as long as pool is
     * running, we get tasks from getTask. If it returns null then the
     * worker exits due to changed pool state or configuration
     * parameters.  Other exits result from exception throws in
     * external code, in which case completedAbruptly holds, which
     * usually leads processWorkerExit to replace this thread.
     * 我们可能从一个初始的任务开始。在这种情况我们不需要去获取第一个任务
     * 另外的,线程池开始运行,我们从队列中获取任务,如果它返回null那么由于改变线程池状态或配置参数
     * 工作线程退出。其他退出结果从异常抛出外面的代码,在这种情况completedAbruptly保留
     * 通常会引导processWorkerExit去取代这个线程。
     *
     *
     * 2. Before running any task, the lock is acquired to prevent
     * other pool interrupts while the task is executing, and then we
     * ensure that unless pool is stopping, this thread does not have
     * its interrupt set.
     * 在运行任何任务之前,锁的获取是防止其他线程池中断在任务执行期间。
     * 我们确保除非线程池正在停止,这个线程不会有他的中断。
     *
     * 3. Each task run is preceded by a call to beforeExecute, which
     * might throw an exception, in which case we cause thread to die
     * (breaking loop with completedAbruptly true) without processing
     * the task.
     * 每个任务执行前都会执行beforeExecute,在这个期间可能会抛出异常,
     * 在这种情况我们将线程杀掉(跳出循环)不处理任务
     *
     * 4. Assuming beforeExecute completes normally, we run the task,
     * gathering any of its thrown exceptions to send to afterExecute.
     * We separately handle RuntimeException, Error (both of which the
     * specs guarantee that we trap) and arbitrary Throwables.
     * Because we cannot rethrow Throwables within Runnable.run, we
     * wrap them within Errors on the way out (to the thread's
     * UncaughtExceptionHandler).  Any thrown exception also
     * conservatively causes thread to die.
     * 4,假设beforeExecute执行正常,我们执行任务,收集它抛出的任何异常
     * 然后发送给afterExecute。我们分别处理运行时隐藏,错误和任意的throwable.
     * 因为我们不能再次抛出throwalbe在run方法中,我们包装他们在错误这种方法
     *
     *
     * 5. After task.run completes, we call afterExecute, which may
     * also throw an exception, which will also cause thread to
     * die. According to JLS Sec 14.20, this exception is the one that
     * will be in effect even if task.run throws.
     * 在任务执行完成,我们调用afterExecute,这个也可能抛出一个异常,
     * 也会导致线程死亡。根据JSL Sec14.20 这个异常将会生效,即使任务丢失。
     *
     * The net effect of the exception mechanics is that afterExecute
     * and the thread's UncaughtExceptionHandler have as accurate
     * information as we can provide about any problems encountered by
     * user code.
     *
     * @param w the worker
     */
    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        //获取第一个任务
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            //如果执行任务失败,则线程会终止。
            while (task != null || (task = getTask()) != null) {
                //执行完每个任务都要重新获取锁
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt、
                //如果线程池停止,确保线程中断
                //如果不是,确保线程不是中断,这个要求一个再次检测在第二种情况去
                //处理shutdownNow竞赛在清除中断的期间。
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    //执行钩子方法,
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        //将异常传到执行后的钩子方法中
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    //就算执行失败也还是会将完成的任务加一。
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

获取任务

 /**
     * Performs blocking or timed wait for a task, depending on
     * current configuration settings, or returns null if this worker
     * must exit because of any of:
     * 执行阻塞或超时为一个任务,依赖当前设置或返回null如果这个工作线程必须退出
     * 因为下面的某种情况之一:
     * 1. There are more than maximumPoolSize workers (due to
     *    a call to setMaximumPoolSize).
     *    由于线程数超过了最大线程数(由于动态设置了最大线程数—)
     * 2. The pool is stopped.
     *   线程池停止
     * 3. The pool is shutdown and the queue is empty.
     * 线程池shutdown并且任务队列已经空了
     * 4. This worker timed out waiting for a task, and timed-out
     *    workers are subject to termination (that is,
     *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
     *    both before and after the timed wait, and if the queue is
     *    non-empty, this worker is not the last thread in the pool.
     * 工作线程超时等待一个工作,并且超时工作线程终止(这是允许核心线程超时或工作数大于核心工作线程数
     * 不管在超时之前还是之后,如果队列不为空,这个工作线程不是最后一个线程在线程池。
     * @return task, or null if the worker must exit, in which case
     *         workerCount is decremented
     */
    private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            //允许核心线程超时或当前工作线程数大于核心工作线程的大小
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            //如果线程超过了最大线程数或((设置核心线程是可以超时或线程超过了核心线程数)且下面的获取任务超时了)
            //且(工作线程大于1或工作队列为空)
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    //如果返回null,runWorker方法调用processWorkerExit时如果当前工作线程大于1或工作队列为空则不会
                    //新建线程
                    return null;
                continue;
            }

            try {
                //线程池中线程的超时时间是通过这里从阻塞队列中获取任务设置超时时间实现的。
                //当获取一个任务超过了设置的超时时间将会返回null,当获取任务为null时,在
                //执行任务的方法中会做出相应的处理。
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

任务运行失败或中断执行的方法

有些执行失败可能是任务抛出异常需要重新创建工作线程,有些是因为线程池要关闭了。

/**
     * Performs cleanup and bookkeeping for a dying worker. Called
     * only from worker threads. Unless completedAbruptly is set,
     * assumes that workerCount has already been adjusted to account
     * for exit.  This method removes thread from worker set, and
     * possibly terminates the pool or replaces the worker if either
     * it exited due to user task exception or if fewer than
     * corePoolSize workers are running or queue is non-empty but
     * there are no workers.
     * 执行清除和记录为死亡的工作线程。只有从工作线程调用,除非completedAbruptly被设置,
     * 假设workerCount已经被调整了。这个方法将这个线程从工作线程集合中移除,并且
     * 可能终止线程池或取代工作线程如 它退出是因为执行任务抛出议程或当前工作的线程数
     * 少于核心工作线程活队列非空但是没有工作线程了。
     *
     *
     * @param w the worker
     * @param completedAbruptly if the worker died due to user exception
     */
    private void processWorkerExit(Worker w, boolean completedAbruptly) {
        //如果completedAbruptly为false说明没有抛出异常,任务被正常之执行了。
        //调整工作线程数
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //将当前线程的完成任务的数量加到completedTaskCount
            completedTaskCount += w.completedTasks;
            //从工作线程集合中移除
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

        //尝试去关闭
        tryTerminate();

        int c = ctl.get();
        //如果线程池运行状态小于STOP,
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                //如果任务不是中断的,则为核心工作线程数。如果课中断则为0.
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                //核心线程是不会超时且队列不为空,最小值设置为1
                //确保在核心工作线程能超时销毁时,如果有任务则需要至少有一个线程在处理任务
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                //这里主要是为了防止maximum的线程毁灭时造成线程又加一,只有核心线程毁灭时才会加一

                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
    }

构造方法


    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

   
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

   
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

提供了四个构造方法,参数最多的构造方法需要的参数有corePoolSize核心线程数,maximumPoolSize最大线程数,

keepAliveTime空闲时间,unit时间单位,workQueue工作任务队列,threadFactory创建线程工厂,handler拒绝任务策略七个参数。其中任务拒绝策略,线程工厂方法有默认的设置。所以最少的参数是五个参数。

内部运行原理

核心线程数和最大线程数

ThreadPoolExecutor will automatically adjust the pool size (see getPoolSize()) according to the bounds set by corePoolSize (see getCorePoolSize()) and maximumPoolSize (see getMaximumPoolSize()). When a new task is submitted in method execute(Runnable), and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full. By setting corePoolSize and maximumPoolSize the same, you create a fixed-size thread pool. By setting maximumPoolSize to an essentially unbounded value such as Integer.MAX_VALUE, you allow the pool to accommodate an arbitrary number of concurrent tasks. Most typically, core and maximum pool sizes are set only upon construction, but they may also be changed dynamically using setCorePoolSize(int) and setMaximumPoolSize(int).

当一个新任务提交并且当前线程比corePoolSize小,一个新的线程将会被创建去处理请求,及时其他工作线程是
空闲的。如果当前线程数超过了corePoolSize但是小于maximumPoolSize线程,一个新的线程将会被创建只在队
列满的时候。通过设置corePoolSize和maximumPoolSize一样的值,你创建一个固定大小的线程池。 通过设置
maximumPoolSize到一个本质上是无线的值比如Integer最大值,你允许池 任意的调整并发任务数。大多数情况
下,core和maximum的大小设置只在构建时,但是他们也能够动态的改变使用setCorePoolSize和
setMaximumPoolSize

钩子方法

This class provides protected overridable beforeExecute(Thread, Runnable) and afterExecute(Runnable, Throwable) methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries. Additionally, method terminated() can be overridden to perform any special processing that needs to be done once the Executor has fully terminated.

If hook or callback methods throw exceptions, internal worker threads may in turn fail and abruptly terminate.

这个类提供了受保护的可覆盖的beforeExecute,afterExecute方法,他们将会被调用 * 在执行每个任务之前和之后。这可用被用来操纵执行环境。比如重新启动,ThreadLocal, * 收集统计,或添加日志记录。此外,terminated方法能被重写执行任何特殊处理(需要去 * 执行一次之后彻底的销毁)

如果钩子或回调方法抛出异常,内部工作线程可能失败和突然终止。

 

拒绝任务 

New tasks submitted in method execute(Runnable) will be rejected when the Executor has been shut down, and also when the Executor uses finite bounds for both maximum threads and work queue capacity, and is saturated. In either case, the execute method invokes the RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor) method of its RejectedExecutionHandler. Four predefined handler policies are provided:

  1. In the default ThreadPoolExecutor.AbortPolicy, the handler throws a runtime RejectedExecutionException upon rejection.
  2. In ThreadPoolExecutor.CallerRunsPolicy, the thread that invokes execute itself runs the task. This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted.
  3. In ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped.
  4. In ThreadPoolExecutor.DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which can fail again, causing this to be repeated.)

It is possible to define and use other kinds of RejectedExecutionHandler classes. Doing so requires some care especially when policies are designed to work only under particular capacity or queuing policies.

新任务通过execute方法提交将会被拒绝当执行器已经关闭,或者执行器使用有界且执行器的线程已经最大且队列
已满,饱和的。其中的任何一种情况,execute方法调用RejectedExecutionHandler 的rejectedExecution方
法。有四种预先定义的处理策略提供:
默认的处理策略是ThreadPoolExecutor.AbortPolicy。这个处理类会抛出一个运行时异常在拒绝的时候 

ThreadPoolExecutor.CallerRunsPolicy这个处理类会让提交任务的线程自己去执行任务
 提供了一个简单的反馈控制机制,这个机制将会减缓新任务的提交速度

ThreadPoolExecutor.DiscardPolicy这个处理类什么都没有做。也就是吧任务抛弃了。 

ThreadPoolExecutor.DiscardOldestPolicy这个处理类,如果执行器没有关闭。
在队列首部的任务将会被抛弃,染回执行器再重新提交任务(这可能再次的失败,导致重复这个步骤)

任务的入队

Any BlockingQueue may be used to transfer and hold submitted tasks. The use of this queue interacts with pool sizing:

  • If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
  • If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
  • If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.
任何阻塞队列可以被用来传输和持有提交的任务,队列的使用和线程池大小相互影响。
   如果少于核心线程数的线程在运行,Executor总是优先创建一个新的线程而不是进行入队。
   如果有大于等于corePoolSize的线程正在运行,Executor总是优先使用入队 而不是添加一个新的线程。
   如果一个请求不能被入队,一个新的线程会被创建除非这个创建后会超过maximumPoolSize如果会超过则这个任务将会被拒绝。
There are three general strategies for queuing:
  1. Direct handoffs. A good default choice for a work queue is a SynchronousQueue that hands off tasks to threads without otherwise holding them. Here, an attempt to queue a task will fail if no threads are immediately available to run it, so a new thread will be constructed. This policy avoids lockups when handling sets of requests that might have internal dependencies. Direct handoffs generally require unbounded maximumPoolSizes to avoid rejection of new submitted tasks. This in turn admits the possibility of unbounded thread growth when commands continue to arrive on average faster than they can be processed.
  2. Unbounded queues. Using an unbounded queue (for example a LinkedBlockingQueue without a predefined capacity) will cause new tasks to wait in the queue when all corePoolSize threads are busy. Thus, no more than corePoolSize threads will ever be created. (And the value of the maximumPoolSize therefore doesn't have any effect.) This may be appropriate when each task is completely independent of others, so tasks cannot affect each others execution; for example, in a web page server. While this style of queuing can be useful in smoothing out transient bursts of requests, it admits the possibility of unbounded work queue growth when commands continue to arrive on average faster than they can be processed.
  3. Bounded queues. A bounded queue (for example, an ArrayBlockingQueue) helps prevent resource exhaustion when used with finite maximumPoolSizes, but can be more difficult to tune and control. Queue sizes and maximum pool sizes may be traded off for each other: Using large queues and small pools minimizes CPU usage, OS resources, and context-switching overhead, but can lead to artificially low throughput. If tasks frequently block (for example if they are I/O bound), a system may be able to schedule time for more threads than you otherwise allow. Use of small queues generally requires larger pool sizes, which keeps CPUs busier but may encounter unacceptable scheduling overhead, which also decreases throughput.
这里有三种普遍的策略为队列
直接处理:SynchronousQueue是一个好的默认选择为一个工作队列,它直接将任务传递给线程而不用持有他们。
如果没有线程立刻能够去执行提交的任务,它将会失败。这个策略会避免锁定当请求的处理集有内部依赖关系。
Direct handoffs通常需要一个没有边界的maximumPoolSize去避免新的任务会被拒绝。这反过来有允许了当命
令到达的平均速度超过线程处理任务的速度时,无线线程增长的可能性
无边界队列:使用一个无边界队列比如一个没有预先设定容量的LinkedBlockingQueue 将会导致新的任务在一个
队列等待当素有的corePoolSize线程忙碌的时候。因此,没有超过 corePoolSize大小的线程会被创建(并且
maximumPoolSize的值的设置是没有效果的) 这可能是合适的当每个任务都是完全独立的,因此任务之间的执行
不会相互影响。比如一个网页服务。这个形式的队列能用于平滑的处理短暂爆发的请求,它允许当指令到达的平均
速度比他处理的速度快时, 无边界工作队列增长的可能性。
有界队列。一个有界队列(比如ArrayBlockingQueue)帮助防止资源耗尽当使用 有限的maximumPoolSizes.但
是可能更难做到调整和控制。队列大小和最大线程池大小可能交换:使用大的队列和小的线程池减小cpu的使用,
系统资源和上下文切换的消耗,但是 可以导致认为的低吞吐量。如果任务频繁的阻塞,一个系统可能去计划更多
的线程比你原本允许的。使用小的队列通常需要打的线程池,这会是cpu持续的繁忙,但是可能遭遇调度频繁,也
会导致吞吐率降低。

线程存活时间 

If the pool currently has more than corePoolSize threads, excess threads will be terminated if they have been idle for more than the keepAliveTime (see getKeepAliveTime(TimeUnit)). This provides a means of reducing resource consumption when the pool is not being actively used. If the pool becomes more active later, new threads will be constructed. This parameter can also be changed dynamically using method setKeepAliveTime(long, TimeUnit). Using a value of Long.MAX_VALUE TimeUnit.NANOSECONDS effectively disables idle threads from ever terminating prior to shut down. By default, the keep-alive policy applies only when there are more than corePoolSize threads. But method allowCoreThreadTimeOut(boolean) can be used to apply this time-out policy to core threads as well, so long as the keepAliveTime value is non-zero.

如果线程池当前有超过核心线程数的线程,超过的线程如果空闲的时间超过了 keeplive的时间将会被终止。它提供了一个种方法减少资源消耗在线程池没有 * 活跃的使用时。如果现成词在稍后变的活跃,新的线程将会被创建。这个参数也可以动态的改变。使用一个大的数有效不能使空闲的线程从任何时候终结在线程池关闭前。 默认情况下keep-alive方针应用只有在超过核心线程大小的线程上,但是可以通过方法 * allowCoreThreadTimeOut设置将这个超时方针应用到核心线程上,只要keepAliveTime不是非零的。

 

如何创建一个新的线程

New threads are created using a ThreadFactory. If not otherwise specified, a Executors.defaultThreadFactory() is used, that creates threads to all be in the same ThreadGroup and with the same NORM_PRIORITY priority and non-daemon status. By supplying a different ThreadFactory, you can alter the thread's name, thread group, priority, daemon status, etc. If a ThreadFactory fails to create a thread when asked by returning null from newThread, the executor will continue, but might not be able to execute any tasks. Threads should possess the "modifyThread" RuntimePermission. If worker threads or other threads using the pool do not possess this permission, service may be degraded: configuration changes may not take effect in a timely manner, and a shutdown pool may remain in a state in which termination is possible but not completed.

新线程被创建使用ThreadFactory.如果么有其他说明,Executors的defaultThreadFactory 将会被使用(也就是没有指定线程工厂的话会使用Executors的默认线程工厂), 默认的线程工厂创建的线程都在一个相同的ThreadGroup并且有相同的优先级和非守护状态通过提供一个不同的线程工厂,你能改变线程的名称,线程的group,优先级,守护状态,等等。 如果线程工厂创建线程失败当请求一个新线程返回null时,executor将继续但是不能去执行任何任务。线程应该拥有修改线程。如果工作线程或其它线程使用线程池没有次有许可,服务可能会降级:配置更改可能不会及时影响,关闭线程池可能保留一个终止状态但是没有完成。

按需构建

By default, even core threads are initially created and started only when new tasks arrive, but this can be overridden dynamically using method prestartCoreThread() or prestartAllCoreThreads(). You probably want to prestart threads if you construct the pool with a non-empty queue.

默认的,及时核心线程是最初创建和只有新的任务到达时创建,但是这能被动态覆盖通过prestartCoreThread方
法。你可能想去预先启动线程如果你构造了一个队列不为空的线程池。

 参考资料:

jdk1.8

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值