ThreadPoolExecutor源码解析

本文详细解析了ThreadPoolExecutor的实现原理,包括其构造方法、核心参数、线程池状态及转换,以及execute、addWorker、runWorker等关键方法的执行流程。通过源码解读,揭示了线程池的工作机制和拒绝策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

    在《阿里巴巴开发手册》中有对针对线程池的使用有着明确的要求,原文如下:

【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 
说明:Executors 返回的线程池对象的弊端如下: 
1)FixedThreadPool 和 SingleThreadPool:   允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。 
2)CachedThreadPool 和 ScheduledThreadPool:   允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。 

    那么为什么开发手册会选择ThreadPoolExecutor呢?今天通过这篇文章可以为大家揭开ThreadPoolExecutor这层神秘的面纱。

二、FixedThreadPool 等是怎么实现的?

FixedSizeThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

SingleThreadPool

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

CachedThreadPool

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

ScheduledThreadPool

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
/** ScheduledThreadPoolExecutor */
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}
/** super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue()); */
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {

    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

    由上可知,FixedThreadPool 等都是基于ThreadPoolExecutor来实现的,那么FixedThreadPool的底层实现原理到底是什么呢?接下来我们来看看ThreadPoolExecutor源码

三、ThreadPoolExecutor源码解析

核心构造方法

//核心的构造方法
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {

    //先对于参数的数值进行判断,即是否小于0或者最大线程数是否小于核心线程数
    //若不符合规范则抛出异常
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();

    //然后对任务队列以及线程工厂和拒绝策略进行空指针判断,若为空则抛出异常
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();

    //若都符合规范则对于ThreadPoolExecutor中的变量进行赋值
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

构造方法的参数含义

1.corePoolSize:线程池核心线程数大小。
2.maximumPoolSize:线程池线程数最大值,达到最大值后线程池不会再增加线程执行任务。 
3.keepAliveTime:线程池中超过corePoolSize数目的空闲线程最大存活时间,allowCoreThreadTimeOut为 true的核心线程有效时间。 
4.unit:时间单位。 
5.workQueue:阻塞任务队列,用于保存任务以及为工作线程提供待执行的任务。 
6.threadFactory:线程工厂,线程生成器。 
7.handler:当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理。 
8.ThreadPoolExecutor内部有实现4个拒绝策略,默认为AbortPolicy策略: 
    (1) CallerRunsPolicy:由调用execute方法提交任务的线程来执行这个任务。 
    (2) AbortPolicy:抛出异常RejectedExecutionException拒绝提交任务,默认的拒绝策略。
    (3) DiscardPolicy:直接抛弃任务,不做任何处理。 
    (4) DiscardOldestPolicy:去除任务队列中的第一个任务,重新提交。

拒绝策略如何实现?

    ThreadPoolExecutor是在其内部有四个内部类,分别对应四种拒绝策略,他们均是继承RejectedExecutionHandler接口,实现rejectedExecution方法,以此来实现拒绝策略的具体处理过程。

① CallerRunsPolicy内部类

//CallerRunsPolicy拒绝策略:让调用该任务的线程来执行该任务
public static class CallerRunsPolicy implements RejectedExecutionHandler {
    //构造方法
    public CallerRunsPolicy() { }

    //在调用者的线程中执行任务r,除非执行器已经关闭,在这种情况下任务将被丢弃。
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        //先判断线程池是否被关闭
        if (!e.isShutdown()) {
            //如果还没被关闭,则运行此任务
            r.run();
        }
    }
}

② AbortPolicy内部类

//AbortPolicy拒绝策略:拒绝任务并抛出RejectedExecutionException异常
public static class AbortPolicy implements RejectedExecutionHandler {
    //构造方法
    public AbortPolicy() { }

    //拒绝任务并抛出RejectedExecutionException异常
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}

③ DiscardPolicy内部类

//DiscardPolicy拒绝策略:拒绝任务但不抛出异常
public static class DiscardPolicy implements RejectedExecutionHandler {
    //构造方法
    public DiscardPolicy() { }

    //什么也不做,直接丢弃
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
}

④ DiscardOldestPolicy内部类

//DiscardOldestPolicy拒绝策略:丢弃同步队列最前面的那个任务,然后重新尝试执行任务(调用execute方法)
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    //构造方法
    public DiscardOldestPolicy() { }

    //丢弃队列中最前面的任务,然后重新尝试执行任务(调用execute方法)
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    //先判断当前线程池是否为关闭状态
    if (!e.isShutdown()) {
            e.getQueue().poll();
            e.execute(r);
        }
    }
}

ThreadPoolExecutor的变量含义

//AtomicInteger(ctl)是一个32位的整数,为了将状态和数量放在一起。
//所以高3位用于表示表示状态,低29位表示数量。
//初始化线程数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

//Integer.SIZE = 32,COUNT_BITS = 32 - 3 = 29
private static final int COUNT_BITS = Integer.SIZE - 3;

//CAPACITY用32位表示:0001 1111 1111 1111 1111 1111 1111 1111
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

//RUNNING用32位表示:1110 0000 0000 0000 0000 0000 0000 0000
//能接受新任务,队列中的任务可继续运行
private static final int RUNNING    = -1 << COUNT_BITS;

//SHUTDOWN用32位表示:0000 0000 0000 0000 0000 0000 0000 0000
//不再接受新任务,队列中的任务仍可继续执行
private static final int SHUTDOWN   =  0 << COUNT_BITS;

//STOP用32位表示:0010 0000 0000 0000 0000 0000 0000 0000
//不再接受新任务,不再执行队列中的任务,中断所有执行中的任务(发中断消息)
private static final int STOP       =  1 << COUNT_BITS;

//TIDYING用32位表示:0100 0000 0000 0000 0000 0000 0000 0000
//所有任务均已终止,workerCount的值为0,转到TIDYING状态的线程即将要执行terminated()钩子方法.
private static final int TIDYING    =  2 << COUNT_BITS;

//TERMINATED用32位表示:0110 0000 0000 0000 0000 0000 0000 0000
//terminated()方法执行结束
private static final int TERMINATED =  3 << COUNT_BITS;

//用于保存任务并将任务传递给工作线程的队列。
private final BlockingQueue<Runnable> workQueue;

//锁
private final ReentrantLock mainLock = new ReentrantLock();

//设置包含池中的所有工作线程。只有在持有主锁时才能访问。
private final HashSet<Worker> workers = new HashSet<Worker>();

//支持等待终止的等待条件
private final Condition termination = mainLock.newCondition();

//返回池中同时存在的最大线程数。
private int largestPoolSize;

//完成任务的计数器。仅在工作线程终止时更新。仅在主锁下访问。
private long completedTaskCount;

//线程工厂,新建线程池时带入,用来创建新的线程
private volatile ThreadFactory threadFactory;

//拒绝策略,默认是AbortPolicy,会在构造方法中赋值的
//AbortPolicy :拒绝任务并抛出RejectedExecutionException异常;
//DiscardPolicy:拒绝任务但不抛出异常;
//DiscardOldestPolicy:丢弃队列中最前面的任务,然后重新尝试执行任务(调用execute方法);
//CallerRunsPolicy:调用线程执行该任务;
private volatile RejectedExecutionHandler handler;

//当线程数量超过corePoolSize时,多出来的线程数量的在空闲时的存活时间
private volatile long keepAliveTime;

// 如果为false(默认值),核心线程即使在空闲时也保持活动状态。
// 如果是,核心线程使用keepAliveTime来超时等待工作。
private volatile boolean allowCoreThreadTimeOut;

//线程池中最大的核心线程的数量,核心线程即为即使处于等待状态也不会被销毁的线程
private volatile int corePoolSize;

//线程池允许的最大线程数
private volatile int maximumPoolSize;

//默认的拒绝策略:拒绝任务并抛出RejectedExecutionException异常
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

ThreadPoolExecutor线程池的几个状态

状态描述二进制
RUNNING线程池正常运行,可以接受新的任务并处理队 列中的任务1110 0000 0000 0000 0000 0000 0000 00 00
SHUTDOWN关闭状态,不再接受新的任务,但是会执行队 列中的任务。在线程池处于 RUNNING 状态 时,调用 shutdown()方法会使线程池进入到 该状态。(finalize() 方法在执行过程中也会 调用shutdown()方法进入该状态)0000 0000 0000 0000 0000 0000 0000 0000
STOP不再接受新任务,不处理队列中的任务,中断 进行中的任务。在线程池处于 RUNNING 或 SHUTDOWN 状态时,调用 shutdownNow() 方法会使线程池进入到该状 态0010 0000 0000 0000 0000 0000 0000 0000
TIDYING所有任务已经终止,workerCount为0,线程 状态转换到TIDYING,线程池进入该状态后 会调用 terminated() 方法进入 TERMINATED 状态0100 0000 0000 0000 0000 0000 0000 0000
TERMINATEDterminate()函数执行完成后进入该状态0110 0000 0000 0000 0000 0000 0000 0000

线程池状态之间的转换

/**
 * 各状态之间可能的转变有以下几种:
 * 1.RUNNING -> SHUTDOWN:
 *    调用了shutdown方法,线程池实现了finalize方法。
 *    在finalize内调用了shutdown方法。
 *    因此shutdown可能是在finalize中被隐式调用的
 * 2.(RUNNING or SHUTDOWN) -> STOP
 *    调用了shutdownNow方法
 * 3.SHUTDOWN -> TIDYING
 *    当队列和线程池均为空的时候
 * 4.STOP -> TIDYING
 *    当线程池为空的时候
 * 5.TIDYING -> TERMINATED
 *    terminated()方法调用完毕
 */

四、线程池的相关流程

execute执行的过程

// 在将来的某个时候执行给定的任务。任务可以在新线程中执行,也可以在现有的池线程中执行。
// 如果任务无法提交执行,可能是因为这个执行器已经关闭,也可能是因为它的容量已经达到,
// 那么该任务将由当前拒绝策略处理。
public void execute(Runnable command) {
    //空指针判断检查
    if (command == null)
        throw new NullPointerException();

    //获取当前线程池信息,状态+线程数量
    int c = ctl.get();

    //workerCountOf是获取当前线程池的线程数量
    //判断当前线程池的线程数量是否小于corePoolSize
    if (workerCountOf(c) < corePoolSize) {
        //如果当前线程池的线程数量小于corePoolSize
        //就将当前任务线程添加进线程池然后返回
        if (addWorker(command, true))
            return;
        //如果addWorker方法没有将此线程成功的加入线程池
        //则再次获取当前线程池的状态和线程数量
        c = ctl.get();
    }

    // isRunning表示先判断当前线程池是否在运行状态
    // 如果线程池处于运行状态,则将任务存放在任务队列
    if (isRunning(c) && workQueue.offer(command)) {
        //再次获取线程池的信息
        int recheck = ctl.get();
        //先检查当前线程池是否处于运行状态
        //如果不处于运行状态,则将刚刚workQueue.offer的任务从任务队列中移除
        if (! isRunning(recheck) && remove(command))
            //如果线程池不处于运行状态,并且移除成功
            //则按照拒绝策略来对此任务进行处理
            reject(command);
        //检查当前线程池的线程数量是否为0
        else if (workerCountOf(recheck) == 0)
            根据情况是否要将新起一个线程
            addWorker(null, false);
    }
    //如果线程池不处于运行状态或者添加任务进任务队列失败了
    //就新起一个线程
    else if (!addWorker(command, false))
        //如果新起线程失败,则对任务按照拒绝策略进行处理
        reject(command);
}

addWorker的执行过程

//线程池尝试新增一个线程,并执行任务
//core表示:如果真使用corePoolSize作为边界,则使用maximumPoolSize。
private boolean addWorker(Runnable firstTask, boolean core) {
    //注意
    retry:
    for (;;) {
        //获取当前线程池的信息
        int c = ctl.get();
        //获取当前线程池的运行状态
        int rs = runStateOf(c);

        //如果当前线程池的运行状态为SHUTDOWN/STOP/TIDYING/TERMINATED
        //并且 当前线程池的状态为SHUTDOWN以及任务为空以及任务队列为空
        //则直接返回false
        //一句话,就是判断线程池是否处于RUNNING状态且任务不为空
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            //获取当前的线程数
            int wc = workerCountOf(c);
            //若线程池超过最大容量,或大于设定的容量
            //corePoolSize与maximumPoolSize均为传入的参数
            //那么直接返回false
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            //那么采用cas机制,将线程池计数器扩增1,跳出标签
            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
        }
    }

    //上面若将线程池计数器加1了
    //这里就要对线程池扩增了
    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 {
                //获取线程池状态
                int rs = runStateOf(ctl.get());
                //若线程池状态为running状态
                //或为SHUTDOWN并且传入的线程为空
                if (rs < SHUTDOWN ||
                    (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)
            //回滚当前新起线程操作
            //移除当前新增失败的线程
            //将线程池计数器减1
            //尝试中断线程池或者中断当前线程
            addWorkerFailed(w);
    }
    return workerStarted;
}

runWorker执行的过程

//执行线程任务
final void runWorker(Worker w) {
    //获取当前线程
    Thread wt = Thread.currentThread();
    //获取当前线程该执行的任务
    Runnable task = w.firstTask;
    //先将当前线程代表的任务变为null
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        //循环从缓冲队列内拿出task,直到task内为空
        while (task != null || (task = getTask()) != null) {
            //获取锁
            w.lock();

            //当前的线程池状态为STOP/TIDYING/TERMINATED
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 //或 现在已经中断且当前线程池的状态为STOP/TIDYING/TERMINATED
                 (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);
    }
}

getTask执行过程

//从线程池内获取一个task,成功返回一个Runnable的task,失败返回null。
private Runnable getTask() {
    //超时标志,轮询标志位,表明轮询是否超时
    boolean timedOut = false;

    for (;;) {
        //获取当前线程池信息
        int c = ctl.get();
        //获取当前线程池的运行状态
        int rs = runStateOf(c);

        //如果线程池的状态为SHUTDOWN/STOP/TIDYING/TERMINATED
        //并且 线程池状态为STOP/TIDYING/TERMINATED 或者 任务队列为空
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            //则减少线程数量
            decrementWorkerCount();
            return null;
        }

        //获取当前的线程数
        int wc = workerCountOf(c);

        //标志位 线程池允许核心线程超时都不销毁 或者 当前线程数大于核心线程数
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        //若当前线程数大于最大线程数 或者 timed 且 timedOut均为true(超时)
        if ((wc > maximumPoolSize || (timed && timedOut))
            //并且当前线程数大于1 或者任务队列为空
            && (wc > 1 || workQueue.isEmpty())) {
            //则线程池中线程数成功减1,返回空
            //否则继续下一轮自旋
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            //根据标志位从缓冲队列内轮询或者直接拿一个task
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                //抛出异常
                workQueue.take();
            //若拿到了则成功返回
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

tryTerminate执行过程

//方法作用:进行状态转换以及中断一个线程
final void tryTerminate() {
    for (;;) {
        //获取当前线程池的信息
        int c = ctl.get();
        //若当前线程池为运行状态
        //或者线程池的状态大于TIDYING,即线程池的状态为TIDYING/TERMINATED
        //或线程池的状态为SHUTDOWN和任务队列不为空
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            //则//返回,此时线程池状态不用做任何变更
            return;

        //若当前线程池的线程数量不为0
        if (workerCountOf(c) != 0) { // Eligible to terminate
            // 给线程池的首个线程发中断消息
            // 进行尝试中断其运行
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

        //获得全局锁
        //设置线程池的状态为
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //将线程池的状态变为TIDYING,ctlOf是将参数1和参数2进行或操作
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    terminated();
                } finally {
                    //将线程状态设置为TERMINATED,ctlOf是将参数1和参数2进行或操作
                    ctl.set(ctlOf(TERMINATED, 0));
                    //给其他线程发消息,告知该线程池即将关闭
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}

五、总结

    总的来说,ThreadPoolExecutor还是花费了相当多的时间来进行解读,而且还有一些看不懂的。只单纯看博客是无法深刻了解ThreadPoolExecutor的,只有自己亲自去看了他的源码,才能有所体会。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值