Java多线程--2、ThreadPoolExecutor详解(二)

      上一篇简单介绍了一下ThreadPoolExecutor的一些比较重要的常量,接下来主要来跟踪一下最主要的execute方法。

      上源码:

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     *
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     *
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     */
    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();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

      代码非常的简洁,一个参数,Runnable类型的变量,前文中我们已经介绍过线程运行的原理,线程最终在执行时,会执行Runnable对象的run方法。接下来,我们将逐步分析代码:

int c = ctl.get();

      获取ctl的值,由于ctl是一个原子整型,通过get方法可以获取到当前的值,前3位标识状态,后29位标识线程数量。

if (workerCountOf(c) < corePoolSize) {

      workerCountOf方法,我们在前文已经介绍过,可以计算出ctl的后29位线程数。corePoolSize为ThreadPoolExecutor构造函数里面的初始值,标识核心线程的运行数量。判定当前线程数小于核心线程数时,进入函数体。

if (addWorker(command, true))

      调用addWorker方法,command为我们传递的Runnable对象,接下来我们来跟踪一下addWorker方法,源码:

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

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            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 {
        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();
                    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;
}

      假设我们第一次调用execute方法,那么ctl的当前值为1110 0000 0000 0000 0000 0000 0000,前3位为Running状态,后29位运行线程数为0。查看addWorker第一段代码,2个无限的循环体:

retry:
for (;;) {
    int c = ctl.get();
    int rs = runStateOf(c);

    // Check if queue empty only if necessary.
    if (rs >= SHUTDOWN &&
        ! (rs == SHUTDOWN &&
           firstTask == null &&
           ! workQueue.isEmpty()))
        return false;

    for (;;) {
        int wc = workerCountOf(c);
        if (wc >= CAPACITY ||
            wc >= (core ? corePoolSize : maximumPoolSize))
            return false;
        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
    }
}

      获取ctl的值,再通过ctl获取线程池状态(runState - rs,下文简称rs),当前rs值应为RUNNING,所以第一个判定:

// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
    ! (rs == SHUTDOWN &&
       firstTask == null &&
       ! workQueue.isEmpty()))
    return false;

      在正常运行的情况下,没有外部调用shutdown方法或者出现异常时,不会通过判定,会直接运行下一段代码,同样为一个无限循环体:

int wc = workerCountOf(c);
if (wc >= CAPACITY ||
    wc >= (core ? corePoolSize : maximumPoolSize))
    return false;

      workCount - wc(下文简称wc),当前活动线程数,在无特殊情况下,第一个判定不会为true,因为CAPACITY的容量很大,第二个判定,core为ture时,判断活动线程数是否大于核心线程数,false时判定是否大于最大池边界值数量,如果判定通过,直接结束方法体,返回false,此时的wc数应为0,不通过判定,直接运行下一步。

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

      compareAndDecrementWorkerCount是对ctl的一个原子操作:

private boolean compareAndIncrementWorkerCount(int expect) {
    return ctl.compareAndSet(expect, expect + 1);
}

   比对expect的值是否等于实际值,如果等于,将当前值加一,返回true。注意:由于ThreadPoolExecutor对象是在一个多线程的环境中,所以可能出现其他的线程在此期间修改过ctl的值,那么此时的设定就会失败,返回一个false值。

      如果设定成功,会直接跳出最外层的循环,如果失败,重新获取ctl的值,再重新判定rs是否发生变更,如果rs发生变更,执行外层下一次循环,如果未变更,执行当前下一次循环。

      假设我们设定成功,此时ctl的值将会变为:1110 0000 0000 0000 0000 0000 0000 0001,查看下一段代码:

boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;

      设定一些局部变量,然后开始一个try-catch方法体:

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 rs = runStateOf(ctl.get());

            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)
        addWorkerFailed(w);
}

      通过上诉代码,我们可以看见一个Worker对象被创建,随后worker的一个全局变量thread被赋值给一个临时变量,而最终会调用这个临时变量的start方法,那么此时的线程就会真正的启动了,随后run方法也会被调用。

private final HashSet<Worker> workers = new HashSet<Worker>();
// ... some code
workers.add(w);

      workers是一个全局变量,用来保存worker对象在内存中的一个持久化存储,在worker保存成功后,workerAdded的值会设置为true,随后调用t.start方法,启动线程。

      下文中,我们将解析一下Worker的代码,来分析线程池是如何实现池的功能的!

猜你喜欢

转载自my.oschina.net/u/3760321/blog/1615188