JUC下的ThreadPoolExecutor源码分析

基于版本JDK1.8

线程池执行流程:

1、查看线程池的execute方法

/**
 *如果任务无法提交执行,可能是因为执行器已关闭,或者由于其容量已达到
 */
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     * 1. 如果线程数量小于核心线程数,以给定的command启动线程,并设置为线程的第一个任务
     * 2. 核心线程已满,则执行入队,成功入队则检查是否需要添加一个线程
     * 3. 创建非核心线程,以给定的command启动线程,并设置为线程的第一个任务,如果创建非核心线程失败,则执行拒绝策略
     */
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        //线程池如果不是RUNNING状态,从阻塞队列中把刚加入的任务移除,执行拒绝策略
        if (!isRunning(recheck) && remove(command))
            reject(command);
        //如果线程数量是否为空,此时又因为workQueue.offer(command)添加了一个任务,就需要添加一个非核心线程
        //什么时候会出现这种情况呢,
        //如:executor.allowCoreThreadTimeOut(true);允许核心线程在空闲时间超过keepAliveTime后,会被终止,因此可能出现线程池没有线程的情况    
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

 2、继续查看addworker方法

/**
 * 在线程池中创建一个新的线程
 * @param firstTask参数为新增线程执行的第一个任务
 * @param 活动线程数>=(core?核心线程数:最大线程数)
 */
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        // x步骤
        // 说人话就是线程池不是RUNNING状态,并且(状态不为SHUTDOWN 或者 任务不为空 或者 队列为空),则直接返回false
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            //获取现有线程数
            int wc = workerCountOf(c);
            //a步骤
            //1、添加核心线程,则判断线程数是否超过核心线程数
            //2、添加非核心线程,则判断线程数是否超过最大线程数
            //是,则返回false
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            //b步骤    
            //cas增加线程数量成功,则通过break retry跳出多重循环,继续执行下方代码    
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get(); 
            //如果状态没有变化,则继续执行步骤a或b
            //如果状态有变化,则跳出for循环,执行x步骤
            if (runStateOf(c) != rs)
                continue retry;
        }
    }
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        //Worker实现了runnale接口,有两个属性,
        //firstTask 创建worker对象时待执行的第一个任务
        //thread 在构建一个Woker对象时,会使用getThreadFactory().newThread(this);赋值给thread
        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());
                //如果线程池处于运行状态(< SHUTDOWN)
                //或者(线程池处于SHUTDOWN并且当前woker线程没有自己的第一个任务)
                //设置workerAdded为true,表示下面步骤启动线程
                if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
                    //检查线程是否启动,启动则抛异常
                    if (t.isAlive()) 
                        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;
}
 

3、继续查看Worker类结构

/**
 * 1、Worker继承了AbstractQueuedSynchronizer 因此也具备了AQS的特征
 * 2、Worker实现了Runnable接口,因此Woker也是
 * 3、AQS具备的特征:阻塞等待队列、共享/独占、公平/非公平、可重入、允许中断
 */
private final class Worker extends AbstractQueuedSynchronizer implements Runnable
{
    final Thread thread;
    Runnable firstTask;
    volatile long completedTasks;
    /**
     * @param firstTask 创建worker并执行的第一个任务
     */
    Worker(Runnable firstTask) {
        setState(-1); 
        this.firstTask = firstTask;
        //*****************************************************************************************
        //当执行woker的thread.start()方法时,本质启动时执行的thread里run方法,而此时的参数是this,也就是Worker的run方法
        //*****************************************************************************************
        this.thread = getThreadFactory().newThread(this);
    }
    //*****************************************************************************************
    //当执行run方法时,最终调用的是ThreadPoolExecutor#runWorker的方法
    //*****************************************************************************************
    public void run() {
        runWorker(this);
    }
    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(); }
}  

4、继续查看runWorker和getTask方法

/**
 * worker的thread线程启动后,本质是执行的thread里的run方法,也就是ThreadPoolExecutor#runWorker方法
 * @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 {
        //循环获取task任务,当队列中不存在任务时,则阻塞当前线程
        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);
                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);
    }
}
/**
 * 获取到任务则执行,获取不到任务则阻塞,具体通过workQueue.take()实现
 */
private Runnable getTask() {
    boolean timedOut = false; 

    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;
        }
    }
}

 提问:

a、假如最大线程数为3,核心线程数为2,设置的非核心线程的最大存活时间为30秒,阻塞队列为1,那么线程池里的线程数变为2的时机是什么时候

首先我们要查看Worker里的getTask逻辑,此时总数3个线程,核心线程为2,任务队列为空,此时三个worker线程中就有一个getTask()会返回null,那么此时runWorker跳出循环执行finally里的 processWorkerExit(w, completedAbruptly)退出逻辑。

private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }
        int wc = workerCountOf(c);
        // allowCoreThreadTimeOut默认为false,表示保留核心线程数,为true,表示线程池中的所有线程都可以被回收掉
        // ==1==此时总线程数为3核心线程数为2,timed为true
        // 注意:当总线程数等于核心线程数时,timed为false
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        //==3==
        //timed 和 timedOut都为true并且任务队列为空
        //则执行cas,执行成功线程数c-1,此时getTask就会返回null,执行cas失败则继续循环获取
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }
        try {
            //==2==
            //timed为true执行workQueue.poll逻辑,如果此时队列为空,就会阻塞keepAliveTime时间
            //keepAliveTime时间一到,就会返回null,如果r为null则timedOut = true;
            //注意:timed为false,则执行workQueue.take()阻塞当前线程
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();    
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        decrementWorkerCount();
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        completedTaskCount += w.completedTasks;
        //此时从workers集合中移除对w的引用,等待GC回收
        workers.remove(w);
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    int c = ctl.get();
    if (runStateLessThan(c, STOP)) {
        if (!completedAbruptly) {
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }
        addWorker(null, false);
    }
}

 5、shutdown和shutdownNow

   5.1、shutdown

 a、shutdown:cas更新SHUTDOWN状态

//advanceRunState(SHUTDOWN);
private void advanceRunState(int targetState) {
    for (;;) {
        //获取当前ctl值
        int c = ctl.get();
        //1.如果状态大于等于SHUTDOWN,也就是SHUTDOWN或者STOP,则break跳出循环
        //2.cas更新SHUTDOWN状态
        if (runStateAtLeast(c, targetState) ||
            ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
            break;
    }
}

b、shutdown:中断所有空闲线程

//private void interruptIdleWorkers() {
//    interruptIdleWorkers(false);
//}
private void interruptIdleWorkers(boolean onlyOne) {
    final ReentrantLock mainLock = this.mainLock;
    //加锁,保证对workers集合的操作是安全的
    mainLock.lock();
    try {
        for (Worker w : workers) {
            Thread t = w.thread;
            //!t.isInterrupted()如果线程未被中断过(不会清除中断标志)
            //w.tryLock()如果加锁成功,证明工作线程是空闲的
            if (!t.isInterrupted() && w.tryLock()) {
                try {
                    //中断线程
                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            //onlyOne如果为true,则只中断第一个空闲线程就跳出循环
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();
    }
}

c、shutdown:拒绝所有新增任务

public void execute(Runnable command) {
    ...
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        //再次线程池不是RUNNING状态,从阻塞队列中把刚加入的任务移除
        if (! isRunning(recheck) && remove(command))
            //移除任务成功后,执行拒绝策略
            reject(command);
        ...
    }
    ...
}

5.2、shutdownNow

a、shutdownNow:cas更新STOP状态

advanceRunState(STOP);
private void advanceRunState(int targetState) {
    for (;;) {
        int c = ctl.get();
        //如果状态大于等于STOP,则break跳出循环
        //cas更新线程池状态为STOP
        if (runStateAtLeast(c, targetState) ||
            ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
            break;
    }
}

b、shutdownNow:中断所有线程

interruptWorkers();
private void interruptWorkers() {
    final ReentrantLock mainLock = this.mainLock;
    //加锁,保证对worker集合的操作只有一个线程
    mainLock.lock();
    try {
        for (Worker w : workers)
            w.interruptIfStarted();
    } finally {
        mainLock.unlock();
    }
}
void interruptIfStarted() {
    Thread t;
    //getState() >= 0 确保Worker已经初始化完成,在runWorker中会把state更新为0或1
    /**
     * final void runWorker(Worker w) {
     *  ...
     *     // tryRelease重写unlock()方法,将state状态设置为0
     *     w.unlock(); // allow interrupts
     *     boolean completedAbruptly = true;
     *     try {
     *         while (task != null || (task = getTask()) != null) {
     *             //lock状态设置为1
     *             w.lock();
     *             ...
     *          } finally {
     *                 task = null;
     *                 w.completedTasks++;
     *                 w.unlock();
     *          }
     *         }
     *         completedAbruptly =    alse;
     *     } finally {
     *         processWorkerExit(w, completedAbr    tly);
     *     }
     * }
     */
    //!t.isInterrupted() Worker里线程未被中断
    if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
        try {
            t.interrupt();
        } catch (SecurityException ignore) {
        }
    }
}

c、shutdownNow:拒绝所有任务

public void execute(Runnable command) {
    ...
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        //再次线程池不是RUNNING状态,从阻塞队列中把刚加入的任务移除
        if (! isRunning(recheck) && remove(command))
            //移除任务成功后,执行拒绝策略
            reject(command);
        ...
    }
    // 线程池状态为SHUTDOWN,并且队列为空,则拒绝创建线程,执行任务
    // 线程池状态为STOP,不管队列是否为空,都拒绝创建线程,执行任务
    else if (!addWorker(command, false))
            reject(command);
}

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // 线程池状态为SHUTDOWN,并且队列为空,则拒绝创建线程
        // 线程池状态为STOP,不管队列是否为空,都拒绝创建线程
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;
    }
    ...
}

 6、线程退出

  a、从阻塞队列中获取任务为null,从workers移除当前线程

private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        // 如果线程池状态为SHUTDOWN 并且 队列为空,getTask()直接返回null
        // 如果线程池状态为STOP,getTask()直接返回null
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            //线程数量减1
            decrementWorkerCount();
            return null;
        }
        int wc = workerCountOf(c);
        // 线程数量大于核心线程数,此时timed为true
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        //当timed和timedOut都为true,并且(线程数大于1 或队列为空),则执行线程数cas减1,并且返回null退出循环
        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;
            //超时了,重新进入循环,上面的代码会判断出来当前线程阻塞超时了,直接返回null    
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}
//getTask()为null,completedAbruptly = false
//processWorkerExit(w, completedAbruptly);
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    ...
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        completedTaskCount += w.completedTasks;
        workers.remove(w);
    } finally {
        mainLock.unlock();
    }
    ...
    int c = ctl.get();
    //线程池小于STOP状态
    if (runStateLessThan(c, STOP)) {
        if (!completedAbruptly) {
            //allowCoreThreadTimeOut为true,并且阻塞队列不为空,那么min为1(表示至少保留1个线程处理任务)
            //allowCoreThreadTimeOut为false,那么min为corePoolSize,表示至少保留corePoolSize个工作线程
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            //如果工作线程大于等于min,则符合保留的最小线程数,直接return,不会调用下面的addWorker新开一个线程了
            if (workerCountOf(c) >= min)
                return; 
        }
        addWorker(null, false);
    }
}

b、执行任务异常,当前线程会被移除,再重新添加一个新线程替补因异常退出的线程

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) {
            ...
        }
        completedAbruptly = false;
    } finally {
        //抛出异常,completedAbruptly此时为true,最终执行退出,并新增一个非核心线程
        processWorkerExit(w, completedAbruptly);
    }
}

private void processWorkerExit(Worker w, boolean completedAbruptly) {
    //工作线程数量减1
    if (completedAbruptly) 
        decrementWorkerCount();
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        completedTaskCount += w.completedTasks;
        workers.remove(w);
    } finally {
        mainLock.unlock();
    }
    ...
    int c = ctl.get();
    //如果线程池状态小于STOP,即RUNNING或SHUTDOWN状态,则需要添加一个非核心线程
    if (runStateLessThan(c, STOP)) {
        ...
        //添加一个非核心线程
        addWorker(null, false);
    }
}

 

扩展:我们知道线程池执行任务逻辑:执行任务,核心线程创建完成后,剩余的任务就会执行入队逻辑,队列满后,再创建非核心线程,那么我怎么才能实现创建线程达到最大数量后,才执行入队逻辑,怎么实现。

这个逻辑tomcat的线程池已经实现了,也就是自定义一个阻塞队列TaskQueue,在offer入队前,判断允许最大线程数是否等于worker数量,是则入队,否则返回false,具体实现如下:

class TaskQueue extends LinkedBlockingQueue<Runnable> {
    private ThreadPoolExecutor parent;

    public void setParent(ThreadPoolExecutor parent) {
        this.parent = parent;
    }

    @Override
    public boolean offer(Runnable o) {
        // 若未绑定线程池,直接入队(避免逻辑错误)
        if (parent == null) {
            return super.offer(o);
        }
        // 关键逻辑:线程数 < 最大线程数时,拒绝入队(迫使线程池创建新线程)
        if (parent.getPoolSize() < parent.getMaximumPoolSize()) {
            return false;
        }
        // 线程数已达最大,正常入队
        return super.offer(o);
    }
}

public class JdkWithTaskQueueDemo {
    public static void main(String[] args) {
        // 1. 创建TaskQueue并绑定线程池
        TaskQueue queue = new TaskQueue();
        // 2. 创建JDK线程池(核心2,最大5,队列容量10)
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, 5, 60, TimeUnit.SECONDS,
                queue,
                new ThreadFactory() { // 自定义线程工厂(方便打印线程名)
                    private final AtomicInteger count = new AtomicInteger(1);
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "worker-" + count.getAndIncrement());
                    }
                },
                new ThreadPoolExecutor.AbortPolicy()
        );
        // 3. 绑定线程池到队列(必须步骤!否则TaskQueue不生效)
        queue.setParent(executor);

        // 测试:提交10个任务
        for (int i = 0; i < 10; i++) {
            int taskId = i;
            executor.execute(() -> {
                try {
                    Thread.sleep(1000); // 模拟任务执行
                    System.out.println("任务" + taskId + "执行,线程:" + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();
    }
}

 

 

 

 

 

posted @ 2023-10-29 14:34  西风51668  阅读(13)  评论(0)    收藏  举报