线程池之ThreadPoolExecutor

1,在idea中进入类

图片.png

2,关键的属性

2,1

/**
     * The queue used for holding tasks and handing off to worker
     * threads.  We do not require that workQueue.poll() returning
     * null necessarily means that workQueue.isEmpty(), so rely
     * solely on isEmpty to see if the queue is empty (which we must
     * do for example when deciding whether to transition from
     * SHUTDOWN to TIDYING).  This accommodates special-purpose
     * queues such as DelayQueues for which poll() is allowed to
     * return null even if it may later return non-null when delays
     * expire.
     */
    private final BlockingQueue workQueue;
  // 任务队列,我们的任务会添加到该队列里面,线程将从该队列获取任务来执行

2.2

/**
     * Set containing all worker threads in pool. Accessed only when
     * holding mainLock.
存放所有worker线程的Set集合.仅在持有主锁时才能访问
     */
    private final HashSet workers = new HashSet();

2.3

 private volatile ThreadFactory threadFactory;//线程工厂

2.4

 /**
     * Handler called when saturated or shutdown in execute.
在执行和关闭时调用的处理程序
     */
    private volatile RejectedExecutionHandler handler;

2.5

 private volatile int corePoolSize;//最下保活work数量
  
  private volatile int maximumPoolSize;//work上限

3,调用过程

   step 1:调用ExecutorService的submit方法
    Future submit(Runnable task);  
    
    step 2:实际上是由AbstractExecutorService
        public Future submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
    
    step 3:调用Executor的execute的方法,这是个接口
    void execute(Runnable command);
    
    step 4:实际是由ThreadPoolExecutor的方法实现
     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)) { //提交我们的额任务到workQueue
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false)) //使用maximumPoolSize作为边界
            reject(command); //还不行?拒绝提交的任务
    }
对addworker的调用会自动检查runstate和workercount,
这样可以防止错误的警报,在不需要的时候,通过返回false来添加线程。

    step 5:
    private boolean addWorker(Runnable firstTask, boolean core) 
    
    
    step 6:
    w = new Worker(firstTask); //包装任务
    final Thread t = w.thread; //获取线程(包含任务)
    workers.add(w);   // 任务被放到works中
    t.start(); //执行任务

4,worker类的分析

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 */

work的run方法将自己传入

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

ThreadPoolExecutor的核心方法

 /**
     * 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
其他情况下,我们从getTask中得到tasks
. If it returns null then the
     * worker exits due to changed pool state or configuration
     * parameters.
如果返回null,然后worker就会退出,由于更改了线程池的状态和配置参数 
 Other exits result from exception throws in
     * external code, in which case completedAbruptly holds, which
     * usually leads processWorkerExit to replace this thread.
  由于外部代码引发的异常,这样会突然的保留,这样会导致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.
如果beforeExecute正常的完成了,我们运行这个任务,获取到任意的异常把它送到afterExecute,我们分开的看这些运行时异常
     * 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.
     *
     * 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
                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);
        }
    }
 while (task != null || (task = getTask()) != null)

getTask

/**
     * 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:
以下这些情况或导致获得的task为空    
 * 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.
当pool关闭或者队列为空
     * 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;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

核心语句:

 Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();

5,总结

摘自<<并发编程的艺术>>


图片.png

ThreadPoolExecutor执行execute方法分下面4种情况。
1)如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步需要获取全局锁)。
2)如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。
3)如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(注意,执行这一步骤需要获取全局锁)。
4)如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。ThreadPoolExecutor采取上述步骤的总体设计思路,是为了在执行execute()方法时,尽可能地避免获取全局锁(那将会是一个严重的可伸缩瓶颈)。在ThreadPoolExecutor完成预热之后(当前运行的线程数大于等于corePoolSize),几乎所有的execute()方法调用都是执行步骤2,而步骤2不需要获取全局

此文章参考自
Java线程池详解(一)

你可能感兴趣的:(线程池之ThreadPoolExecutor)