ThreadPool源码记录

原文地址:
https://www.colabug.com/2114619.html

ThreadPoolExecutor执行execute方法:
这里写图片描述
这个方法执行任务时:

  • 判断当前线程池线程数量是否小于核心线程池大小,是则创建线程并启动,否则到第2步
  • 判断任务队列是否已满,未满则将任务加入阻塞队列,已满则到第3步
  • 判断当前线程池线程数量是否小于最大线程池大小,是则创建线程并启动,否则执行饱和策略

    execute方法:

public void execute(Runnable command) {
    /任务为空,抛出空指针异常
    if (command == null)
        throw new NullPointerException();

    int c = ctl.get();

   /判断当前线程数量是否小于核心线程数
    if (workerCountOf(c) < corePoolSize) {  
        /是则添加一个核心线程(true表示核心线程)到线程池,并且启动线程执行任务(addWorker方法里会启动)
        if (addWorker(command, true))   
            return; /添加成功则返回
        c = ctl.get(); 
    }

    /线程池处于运行状态则向阻塞队列添加该任务
    if (isRunning(c) && workQueue.offer(command)) { 
        int recheck = ctl.get();
        /判断线程池是否处于运行状态,不是就移除刚才添加的任务
        if (! isRunning(recheck) && remove(command))
            /移除成功就执行饱和策略,这样整个方法就结束了
            reject(command);
        /否则若处于运行状态或移除失败,这时无论处于哪种情况任务都在阻塞队列里,判断当前线程数量是否为0
        else if (workerCountOf(recheck) == 0)
            若是则添加一个线程并启动
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

addWorker方法:

boolean addWorker(Runnable firstTask, boolean core) 方法的作用就是创建 Worker 对象并启动这个对象里的线程( Worker 里一个 Thread 类型的字段)。

private final ReentrantLock mainLock = new ReentrantLock();
private final HashSet workers = new HashSet();
private int largestPoolSize;

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

        /如果线程池不处于运行状态,理论上不应该添加一个执行该任务的线程,但如果满足下面三个条件的话就可以通过:
        1. 线程池状态是关闭
        2. 要执行的任务为空
        3. 阻塞队列不为空
        因为线程池关闭后不允许提交任务,但关闭后会执行完阻塞队列的任务,所以允许添加一个firstTask为空的线程
        来帮助执行完阻塞队列里的任务
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            /若当前线程池的线程数量达到了线程池所允许的最大线程数或所指定要添加线程类型的线程数量则返回false
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            /到这里前面的限制条件都通过,现在尝试将线程数量增一,成功则退出最外层的循环
            if (compareAndIncrementWorkerCount(c))
                break retry;
            /失败则重新获取线程池状态,状态改变则从最外层循环开始执行,不变则从内循环开始执行
            c = ctl.get();  
            if (runStateOf(c) != rs)
                continue retry;
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        /构造一个Worker对象,每个Worker对象绑定一个线程
        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());
                /若线程池处于运行状态或处于关闭且firstTask为null
                if (rs  largestPoolSize)
                        largestPoolSize = s;
                    /添加成功
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            /若添加成功则启动线程
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        /若启动失败(t线程为空或添加过程中抛出异常)则执行addWorkerFailed方法
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

runWorker方法:

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); /允许中断,与Worker构造函数的setState(-1)是一对的
    boolean completedAbruptly = true;
    try {
        /获取到任务才进入循环
        while (task != null || (task = getTask()) != null) {
            /加锁,表示非空闲状态
            w.lock();
            /1. 如果线程池状态大于等于STOP并且本线程未中断,则应该执行中断方法
             2. 或者执行Thread.interrupted()方法判断本线程是否中断并且清除中断状态,
                如果发现线程池状态大于等于STOP则执行中断方法。
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();

            try {
                /ThreadPoolExecutor中的beforeExecute(wt, task)方法一个空方法,用来留给继承ThreadPoolExecutor的类
                 来重写该方法并在任务执行前执行
                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 {
                    /ThreadPoolExecutor中的afterExecute(task,thrown)方法也是一个空方法,用来留给继承
                    ThreadPoolExecutor的类来重写该方法并在任务执行后执行
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                /该线程执行的任务加1,即使抛出异常
                w.completedTasks++;
                /释放锁,表示回到空闲状态
                w.unlock();
            }
        }
        /执行到这一步表示是由于获取不到任务而正常退出的,所以completedAbruptly为false
        completedAbruptly = false;
    } finally {
        /无论怎样退出都要执行
        processWorkerExit(w, completedAbruptly);
    }
}

getTask方法:

private Runnable getTask() {
    /表示获取任务是否已超时
    boolean timedOut = false; 

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        /1. 若线程池状态大于等于停止状态,此时线程池不再处理队列的任务,并且会回收所有线程(不管空不空闲),
            所以此时应该把线程池线程数量减1,并且获取的任务为空
         /2. 处于关闭状态且任务队列为空,表示任务队列为空且不会有任务提交,所以线程数减1,并且获取的任务为空
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);
        /是否启用超时机制。当允许核心线程超时或当前线程数超过核心线程则启用
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        /如果线程数量超过线程池所允许的最大线程数或者启用超时机制情况下获取任务超时,理论上应该回收线程。
         但是如果该线程是线程池中的最后一个线程且任务队列不为空就可以不回收,继续运行,要是还有其他线程或者任务队列为空则回收该线程。
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            /尝试将线程数量减1,成功返回null,失败继续从循环开始处开始。这里为什么不是用decrementWorkerCount()
            这种不会失败的方法减1而采用这种方式。是因为 wc > 1,如果线程池不只有一个线程它们互相发现不只一个线程,
            且它们同时执行不会失败的将线程数量减一的方法,到时线程池线程数量可能就为0了,哪么队列中的任务就没线程执行了。
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            /1. 如果启用超时机制就执行poll()方法,在keepAliveTime纳秒内还没获取就返回null2. 如果未启用超时机制就执行take()方法,队列没任务就一直阻塞直到有任务。
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            /到这里就是因为超时获取不到任务
            timedOut = true;
        } catch (InterruptedException retry) {
            /在执行take()过程中被中断并不算超时
            timedOut = false;
        }
    }
}

tryTerminate方法:

final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
         /如果满足下面任意一个条件就没办法到达结束状态
         1. 线程池处于运行状态
         2. 线程池状态是TIDYING或已经是结束状态
         3. 线程池处于关闭状态且任务队列不为空
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
         /当前线程数量不为0也无法到达结束状态
        if (workerCountOf(c) != 0) { 
            /中断一个空闲线程
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
             /尝试将线程池状态设置为TIDYING,失败重循环开始处开始
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    /terminated()是一个空方法,留给继承ThreadPoolExecutor的类覆盖
                    terminated();
                } finally {
                    /尝试将线程池状态设置为TERMINATED
                    ctl.set(ctlOf(TERMINATED, 0));
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }

    }
}

猜你喜欢

转载自blog.csdn.net/z_k_h/article/details/80676738