ThreadPoolExecutor源码阅读

1、重点属性

/** 这个属性很有趣,一个同步的Integer存储着两个值,最高3位放置线程池状态;剩下29位放置worker数量,所以worker最多可以有2^29-1个 */
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
/** 可以看到这几个线程池状态最高位三个有值,其他位都是0 */
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;
/** 获取线程池状态,CAPACITY取反跟c按位一与,哦吼就出来了 */
private static int runStateOf(int c)     { return c & ~CAPACITY; }
/** 获取线程池worker数量,CAPACITY跟c按位一与,哦吼就出来了 */
private static int workerCountOf(int c)  { return c & CAPACITY; }
/** 获取ctl数据,rs是状态,wc是worker数量 */
private static int ctlOf(int rs, int wc) { return rs | wc; }
/** 等待队列,从线程池获取线程的时候不满足条件的时候,就往这里加,然后等待 */
private final BlockingQueue<Runnable> workQueue;
/** worker队列,这个队列其实就是个池子,worker里维护着线程,需要运行就在这里获取。那么为什么用worker包装一下呢,详情见worker部分 */
private final HashSet<Worker> workers = new HashSet<Worker>();
/** 可重入锁,用于锁住重要的代码,其中addWorker里面就锁住了workers和largestPoolSize其中workers因为不是线程安全的,好理解;largestPoolSize也需要改变所以必须加锁 */
private final ReentrantLock mainLock = new ReentrantLock();
private int largestPoolSize;
/** 存活时间,非核心线程,超过这个时间没有用就被回收了 */
private volatile long keepAliveTime;
/** 核心线程数 */
private volatile int corePoolSize;
/** 最大线程数 */
private volatile int maximumPoolSize;

        其中corePoolSize,maximumPoolSize,workQueue是怎么打配合呢?一开始嘛,线程池是空的,后来有个任务提交过来了,这个时候就需要建核心线程。核心线程创建到了corePoolSize之后,再来就往workQueue里面加,让任务等着。如果workQueue也满了,那么就开始创建非核心线程,直到达到maximumPoolSize。再来,那就得按照拒绝策略拒绝任务了。

        ReentrantLock mainLock 为什么是个可重入锁呢?我理解因为在增加worker或者tryTerminate的时候需要反复的lock,例如addWorkerFailed的时候就会出现addWorkerFailed里面lock一次,还没有释放锁就tryTerminate又lock一次。如果是非可重入的,那就锁死了。

2、内部类—worker

private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
    /** Thread this worker is running in.  Null if factory fails. */
    final Thread thread;
    /** Initial task to run.  Possibly null. */
    Runnable firstTask;
    /** Per-thread task counter */
    volatile long completedTasks;
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }
    /** Delegates main run loop to outer 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(); }
    void interruptIfStarted() {
        Thread t;
        if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
            try {
                t.interrupt();
            } catch (SecurityException ignore) {
            }
        }
    }
}

        Worker是个很有意思的内部类,他承担着执行外部提交的任务的工作(实现的run方法)。再继续看Worker,他继承了AbstractQueuedSynchronizer ,他居然是个锁!再进一步看tryLock,结合AbstractQueuedSynchronizer(AQS)JDK并发编程核心_workhardliuzheng的博客-CSDN博客看,他还是个不可重入的锁。那为什么把Worker设计成一个锁呢。根据注释来看,他就是维护线程中断状态的。那好了,看哪里加锁那里尝试获取锁就可以了。可以看到lock只有一处调用runWorker,在运行任务的时候给加锁;那什么时候尝试获取锁呢,interruptIdleWorkers,在尝试中断的时候获取锁。结合起来就是,运行的时候是不能够中断线程的,那么在运行前就给他加锁;在中断前就需要尝试获取锁,获取不到就决不能中断。

        与此同时,Worker还是线程执行的委托类,所有的runable都是委托给worker执行的。我觉得可以理解为,线程池里所有“活着的”线程,都是worker持有的线程。这些线程可能是核心线程,也可能是非核心的。

3、重点方法

execute方法

/** 我们执行的最多的方法,具体的逻辑其实就是上面提到的,那几个参数怎么打配合 */
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();

    int c = ctl.get();
	/** 如果是现在小于核心线程呢,就加入核心数 */
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
	/** 能走到这里,要么是大于核心线程数,要么是没加worker成功,就尝试加入队列 */
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
		/** 这里二次检查一次,因为上面的isRunning和offer是耗时的,达到这一步可能状态已经发生变化了 */
        if (! isRunning(recheck) && remove(command))/** 如果不是运行中,然后移除command,如果移除成功了,就拒绝 */
            reject(command);
        else if (workerCountOf(recheck) == 0) 
            addWorker(null, false);
    }
    else if (!addWorker(command, false)) /** 到这里一定是需要加入非核心线程了,因为队列一定是满了,所以先无脑加一次addWorker,如果还加入失败就得拒绝了 */
        reject(command);
}

addWorker方法

/** 往worker的set里面加入worker */
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
	/** 因为里面有CAS,所以必须死循环 */
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        /** 如果线程处于非运行状态,并且 rs 不等于 SHUTDOWN 且 firstTask 不等于空且且
         *    workQueue 为空,直接返回 false
         *    1. 线程池已经 shutdown 后,还要添加新的任务,拒绝
         *    2. (第二个判断)SHUTDOWN 状态不接受新任务,但仍然会执行已经加入任务队列的任
         *    务,所以当进入 SHUTDOWN 状态,而传进来的任务为空,并且任务队列不为空的时候,是允许添加
         *   新线程的,如果把这个条件取反,就表示不允许添加 worker
		 */
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;
        for (;;) {
            int wc = workerCountOf(c);
			/** 如果超过了线程池最大容量,或者超过了核心或最大线程数(与新建的worker是核心还是非核心有关)则不允许增加worker了 */
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
			/** 增加worker数量,一旦CAS增加成功,那么直接跳出去,不再进入循环 */
            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;
			/** 加锁保护workers的hashset并保护largestPoolSize */
            mainLock.lock();
            try {
                /** 在保持锁定的同时重新检查。在ThreadFactory出现故障或在获取锁之前关闭时退出。 */
                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就是worker里面的线程,线程start之后就会调用worker的run方法,进而进入runWorker开始执行 */
                t.start();
                workerStarted = true;
            }
        }
    } finally {
		/** 如果worker没有启动起来,那么需要降低worker的count同时进入tryTerminate尝试减少空闲worker(没有启动嘛,当然要减少) */
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

tryTerminate方法

/** 尝试终止线程池,只有线程池是shutdown 且 worker和队列都是空,或 线程池是stop且worker是空的 */
final void tryTerminate() {
	/** 死循环,必须把ctl.compareAndSet(c, ctlOf(TIDYING, 0))设置成功才可以,否则一直等下去 */
    for (;;) {
        int c = ctl.get();
		/** 如果线程池是运行中,或状态是TIDYING,或状态是已终止,或状态是shutdow但是队列还没空。这个时候一定不能终止,所以直接return
		* 队列如果为空,也许能终止,但是不为空,一定不能终止。
		*/
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
		/** 如果有worker,那么不能终止,但是需要中断一个空闲的worker,让信号量传递出去
		* 这句话是注释上写的,很令人费解。。。
		*/
        if (workerCountOf(c) != 0) { // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
			/** 中断之后只中断了一个空闲worker,当然也可能一个空闲的都没有。那么需要退出,让外部方法再次进入tryTerminate,再次检查是不是所有worker都停止了 */
            return;
        }
		/** 获取全局锁 */
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {/** CAS设置线程池为待终止 */
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {/** 子类实现的终止方法 */
                    terminated();
                } finally {
					/** 执行完子类后,设置线程池状态是终止 */
                    ctl.set(ctlOf(TERMINATED, 0));
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}

        “但是需要中断一个空闲的worker,让信号量传递出去”。这句话很令人费解。。。。想要理解这句话,需要跟getTask方法结合起来看。getTask是从阻塞队列中获取任务的方法,在runWorker中执行。从下面代码看

Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();

        当队列为空的情况下,会阻塞在那里。那么就明了了,worker有几种状态:1、正在运行;2、队列为空,正在阻塞或worker还没获取到task(worker空闲)。那么如果interruptIdleWorkers中断了一个空闲的worker,那么就会抛出interupt异常,解放getTask的阻塞。被外部捕获之后,会再次进入getTask,那么进入getTask的第一步就是检查是不是线程池是shutdown且队列为空。如果为空了,就返回一个null给runWoker方法,此时runWorker退出循环进入finnaly的processWorkerExit——worker退出动作。再回到tryTerminate里面,中断一个worker之后就return了,因为不知道中断之后是不是还有worker,需要调用tryTerminate再次检查是否可以中断,直到全部worker都终止然后再终止。

        上文提到了runWorker和getTask,我们来看一下这两部分代码

runWorker方法

/** 执行worker方法,Worker类的run方法会调用这个方法 */
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
	/** 获取worker里面的task */
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
		/** 这个判断里面有两步,自己绑定的task不为空,则直接进入循环;如果为空则通过getTask获取队列中的任务赋值给task,
		* 如果获取的到,则进入循环,获取不到则进入finnaly的worker终止方法 
		*/
        while (task != null || (task = getTask()) != null) {
			/** 先锁定worker,这个worker已经运行中
了,不许占用,不许中断 */
            w.lock();
			/** 如果池正在停止,请确保线程被中断;如果没有,请确保线程没有中断。这个需要进行二次检查,用来防止清除中断的时候执行shutdownNow */
            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;/** 要么任务执行完了,要么抛异常了,反正这轮task执行完了,把task设置为空 */
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
		/** 退出后需要把这个worker给终止 */
        processWorkerExit(w, completedAbruptly);
    }
}

getTask方法

/** 从阻塞队列里面获取一个任务 */
private Runnable getTask() {
    boolean timedOut = false; 
	/** 不断的循环,直到获取到任务或者不满足,直接返回null让runWorker退出worker */
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        /** 如果线程池准备终止,而且线程池是stop或等待队列为空 */
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
			/** worker数量减一,并返回null,因为线程池已经准备终止了,需要让worker终止 */
            decrementWorkerCount();
            return null;
        }
        int wc = workerCountOf(c);
        // Are workers subject to culling?
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
		/** 检查一下,是不是需要减少一个worker,需要满足两个条件
		* 1、要么有非核心的worker,要么核心worker是超时的。
		* 2、满足了1还要看一下是不是可以减少一个worker,因为要么队列为空,可以直接减少,要么队列不为空得保留一个worker把队列消耗完
		*/
        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;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值