ThreadPoolExecutor线程池工作原理解析

56 阅读3分钟

申明线程池的创建方式

Executors预置参数新建线程池

使用不当,可能导致潜在风险。

// 缓存线程池,用加速短任务执行。由于最大线程数是整数上限,使用不当可能出现并发度太高导致的效率下降问题。
Executors.newCachedThreadPool();
// 固定线程数线程池,限制并发度。固定线程数不灵活,且阻塞队列大小上限也是整数上限,使用不当可能出现内存OOM问题。
Executors.newFixedThreadPool(5);
// 单线程池,用于顺序执行任务。同上,阻塞队列上限为整数上限,使用不当可能出现内存OOM问题。
Executors.newSingleThreadExecutor();
// 周期调度线程池。由于最大线程数最整数上限,使用不当可能出现并发度太高导致效率下降问题。
Executors.newScheduledThreadPool(1);

ThreadPoolExecutor自定义(推荐)

参数上限制并发数,及队列的容量,以便于线程池更加可控

// 自己定义各参数,一般基于上诉四种预置参数线程池,做一些参数优化。
// 不建议用Executors中预定义的线程池,由于存在一些资源无限制问题。所以建议基于以上缺点自已定义合适的线程池
// 如做了并发控制的缓存线程池
new ThreadPoolExecutor(0, 100,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());

线程池的工作流程

创建线程池并提交任务

// 创建线程池
ExecutorService executor = Executors.newSingleThreadExecutor();
// 执行任务,其中xxxx为任务对象
executor.execute(xxxx);

线程池运行,执行任务

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    // 如果小于核心线程数,则增加新线程处理。
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 如果不能添加新线程,则将任务加入队列中。如果线程池中线程为0,则新增一个(空任务)线程处理。(由于任务已经加入队列了,所以这里不再直接提交任务了)
    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);
}

addworker方法解析

private boolean addWorker(Runnable firstTask, boolean core) {
    // break跳转控制标记
    retry:
    // 循环的检查线程池状态,并更新状态(在达到合适条件后将工作线程数加1)
    for (int c = ctl.get();;) {
        // Check if queue empty only if necessary.
        if (runStateAtLeast(c, SHUTDOWN)
            && (runStateAtLeast(c, STOP)
                || firstTask != null
                || workQueue.isEmpty()))
            return false;

        for (;;) {
            // 再次检查工作线程数情况
            if (workerCountOf(c)
                >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
                return false;
            if (compareAndIncrementWorkerCount(c))
                // 退出检查循环
                break retry;
            c = ctl.get();  // Re-read ctl
            // 检查线程池状态,至少要在RUNING或者SHUTDOWN状态才行继续处理已接收到的任务。
            if (runStateAtLeast(c, SHUTDOWN))
                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 c = ctl.get();
                // 检查线程池运行状态,如果线程池在SHUTDOWN,则增加执行最后的任务。
                // RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED
                if (isRunning(c) ||
                    (runStateLessThan(c, STOP) && firstTask == null)) {
                    if (t.getState() != Thread.State.NEW)
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    workerAdded = true;
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                // 运行新增加的线程
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

运行worker

private final class Worker extends AbstractQueuedSynchronizer implements Runnable
{
   // run方法,线程start调用后的运行方法
   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 {
        // getTask循环从任务队列中拿到任务进行处理
        while (task != null || (task = getTask()) != null) {
            // 获取到任务进行处理,互斥锁
            w.lock();
            // 检查线程池状态,及线程池中断标记情况。当前线程如果收到中断信号则进行中断
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                try {
                    // 运行任务
                    task.run();
                    afterExecute(task, null);
                } catch (Throwable ex) {
                    afterExecute(task, ex);
                    throw ex;
                }
            } finally {
                task = null;
                w.completedTasks++;
                // 释放锁
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

一个线程池中,每个线程都有一个无限循环的runWorker运行,以消费队列中的任务。线程池的核心线程是一直运行着的,在实际使用中需要评估好核心线程数,避免消耗过多资源。(默认是阻塞等待,也可设置从队列中取任务时超时时间,keepAliveTime、allowCoreThreadTimeOut。)

线程池状态说明

线程池状态值的大小比较 RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED

public static final int SIZE = 32;
private static final int COUNT_BITS = Integer.SIZE - 3;
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;
  • RUNNING状态: 线程池可接收任务,可处理已接收任务。(新建线程池后,就处于当前状态)
  • SHUTDOWN状态:线程池不可接收任务,可处理已接收任务。(调用shutdown方法)
  • STOP状态:线程池不可接收任务,不再处理已接收任务,并会中断正在处理的任务。(调用shutdownNow方法)
  • TIDYING状态:线程池不可接收任务,不再处理任务,且所有任务已终止,并执行terminated方法。(SHUTDOWN--任务队列为空、执行中任务为空->TIDYING,STOP--执行中任务为空->TIDYING)
  • TERMINATED状态:线程池彻底终止,当terminated方法执行完毕后,TIDYING->TERMINATED

image.png