关于ThreadPoolExecutor的解析

来源:互联网 发布:冒险岛怪物数据库 编辑:程序博客网 时间:2024/05/02 04:26
public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
            if (runState == RUNNING && workQueue.offer(command)) {
                if (runState != RUNNING || poolSize == 0)
                    ensureQueuedTaskHandled(command);
            }
            else if (!addIfUnderMaximumPoolSize(command))
                reject(command); // is shutdown or saturated
        }

    }

上面是源代码,首先说说poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)这句话说明如果线程数小于corePoolSize ,就会调用addIfUnderCorePoolSize(command),源码如下:

 private boolean addIfUnderCorePoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (poolSize < corePoolSize && runState == RUNNING)
                t = addThread(firstTask);
        } finally {
            mainLock.unlock();
        }
        if (t == null)
            return false;
        t.start();
        return true;
    }

其实就是直接创建新线程执行任务。如果线程数大于或者等于corePoolSize 的话就先插入队列,如果插入队列成功,由于这些判断不是在lock锁里面判断的,所以插入成功之后再次检查runState状态和poolSize数量。如果runState != RUNNING || poolSize == 0则说明两种情况,两种情况的源码处理如下:

 private void ensureQueuedTaskHandled(Runnable command) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        boolean reject = false;
        Thread t = null;
        try {
            int state = runState;
            if (state != RUNNING && workQueue.remove(command))
                reject = true;
            else if (state < STOP &&
                     poolSize < Math.max(corePoolSize, 1) &&
                     !workQueue.isEmpty())
                t = addThread(null);
        } finally {
            mainLock.unlock();
        }
        if (reject)
            reject(command);
        else if (t != null)
            t.start();
    }

第一种情况是插入队列之后,runState状态已经不是running,这样的话,如果任务还在workQueue中,workQueue.remove(command)成功,拒绝执行command;一种是插入队列之后,runState为running,但是线程池没有存活的线程。这样的话,在保证 poolSize < Math.max(corePoolSize, 1) 以及workQueue不为空,需要新建一个新线程来执行完workQueue中的任务。有人肯定会问那如果runState是shutDown状态,然后workQueue中又没有command的情况,我觉得这种情况很少,就算出现了,也不会有问题,要使workQueue不存在command只有两种情况,一种是被getTask执行掉了,一种是shutDownNow把workQueue清空了,但是时间间隙这么少基本上不会出现,就算出现了,也会走第二种情况不会出现问题。

继续上面的讲解,如果poolSize >= corePoolSize而且 command又无法加入workQueue,这样的话会执行addIfUnderMaximumPoolSize,源码如下

 private boolean addIfUnderMaximumPoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (poolSize < maximumPoolSize && runState == RUNNING)
                t = addThread(firstTask);
        } finally {
            mainLock.unlock();
        }
        if (t == null)
            return false;
        t.start();
        return true;
    }

上面的代码和addIfUnderCorePoolSize一模一样就是判断poolSize是否小于maximumPoolSize ,如果是,就新建线程执行command.否则就会调用 reject(command),拒绝任务。

0 0