带着问题看源码(一):ThreadPoolExecutor

571 阅读5分钟

在阅读JDK源码的过程中,伴随着代码量的增多,难免会显得力不从心。在阅读过程中,往往会顾此失彼,在阅读到后面的时候,又会遗忘前面的内容。那么,我觉得我们可以带着问题去阅读源码,有针对性的找到解决方法。

前言

在实际的项目中,我们很少会直接用new的方式去创建一个线程,而是会使用Executors的静态方法去创建一个线程池,其实Executors是调用的ThreadPoolExecutor类去创建不同类型的线程池(当然,《阿里巴巴》规范手册并不推荐我们使用Executors,而是直接使用ThreadPoolExecutor)。

ThreadPoolExecutor一方面可以规范地创建线程,合理控制开辟线程的数据;另一面优化了资源的开销,避免了线程的频繁开辟和关闭。

提出问题

  1. ThreadPoolExecutor线程池如何提高系统性能?
  • 分析:ThreadPoolExecutor线程池在运行时,当有多个线程要运行时,并不会全部创建新线程,减少线程的创建和销毁带来的开销。
  • (1)当线程池的线程运行数小于corePoolSize时,每运行一个线程都会执行new Thread()去创建一个线程并加入到workers集合中;
  • (2)当超过corePoolSize时,要运行的线程会被加入到一个workQueue中,阻塞并等待前面的线程任务完成;
  • (3)在workQueue队列满了之后,当运行的线程数小于maximumPoolSize时,会再创建一个新的线程加入到workers集合中
  • (4)在workQueue队列满了之后,当运行的线程数大于maximumPoolSize时,将会执行拒绝策略

上述过程可在execute(Runnable command)方法中看出,源码:

 public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    
    /*
     *1.如果当前线程运行数据小于corePoolSize时,
     * 创建新线程(线程以Worker内部类的形式)
     */
    if (workerCountOf(c) < corePoolSize) {
        //添加core线程,如果添加成功,则直接返回
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    /*
     *2.判断当前线程池是否在运行状态中并且workQueue有空闲位置,
     *  如果有空位,则加入到阻塞队列等待运行
     */
    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);
    }
    
    //3.当workQueue队列满了,添加非core线程到workers集合中
    else if (!addWorker(command, false)) 
        
        //4.当运行的线程数超过maximumPoolSize时,执行拒绝策略
        reject(command);
}

addWorker方法源码:

/**
 * 根据core标识新建核心线程或者非核心线程并加入到workers集合中
 * @param firstTask 要执行的任务
 * @param core 是否要创建核心线程
 * @return 是否成功创建新线程
 */
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // 判断当前线程池是否处于SHUTDOWN状态
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            
            /*
             *根据core标识,判断当前线程数是否超过corePoolSize或者maximumPoolSize,
             * 超过则创建新线程失败
            /*
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
                
            //CAS判断是否当前是否可创建新线程,否则继续自旋等待    
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read 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 {
        //Worker内部类,实现了Runnable接口,内部带有生成的Thread线程变量
        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 ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                        
                    //创建的新线程(Worker)加入到workers集合中    
                    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;
}
  1. workQueue队列中的任务是什么时候被执行的?怎样执行的?
  • 队列中的任务是在创建的核心线程(Worker内部类)run方法中,在执行完自身任务后,再从workQueue队列取出任务执行。

相关源码:

 private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable
{
 public void run() {
        runWorker(this);
    }
}

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        /**
         * 重点代码:
         * task != null 这段代码是判断当前线程任务是否已执行,未执行则先执行自身的任务
         * (task = getTask()) != null 是从workQueue队列中取出要阻塞的任务
         */
        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 {
                //将已执行的任务置为null
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}    
  1. ThreadPoolExecutor线程池提供了哪些拒绝策略?
  • ThreadPoolExecutor总共提供了四种拒绝策略,分别由四个内部类实现:AbortPolicy(默认拒绝策略)、DiscardPolicy、DiscardOldestPolicy、CallerRunsPolicy
 /**
  * AbortPolicy直接抛出异常,默认拒绝策略
  */
 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());
    }
}

/**
 * DiscardPolicy
 * 直接丢弃,不做任何处理
 */
public static class DiscardPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code DiscardPolicy}.
     */
    public DiscardPolicy() { }

    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
}
/**
 *  DiscardOldestPolicy
 *  当触发拒绝策略,只要线程池没有关闭的话,
 *  丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入
 */
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code DiscardOldestPolicy} for the given executor.
     */
    public DiscardOldestPolicy() { }

    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            e.getQueue().poll();
            e.execute(r);
        }
    }
}

/**
 * CallerRunsPolicy
 * 只要线程池没有关闭,则调用线程直接运行任务
 */
public static class CallerRunsPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code CallerRunsPolicy}.
     */
    public CallerRunsPolicy() { }

    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            r.run();
        }
    }
}

最后

这是我自己在阅读源码想到的一个方法,希望可以给各位带来一些新思路。在阅读源码的时候,我主要是带着这几个问题去寻找答案,也是算大概看懂了一些主流程。当然,还有一些问题,并没有找到答案,希望在接下来的阅读中,能够分析出来。