ThreadPoolExecutor

1 简介

线程池提供了核心线程的暂存,在需要时可以随时使用。同时超过核心线程数的job放入等待队列,当等待队列满时,创建新的线程来处理最新的任务,但是线程总数不超过最大线程数,当创建新线程失败时,执行拒绝策略。

2 ThreadPoolExecutor

2.1execute

提交任务到线程池。如果线程数小于核心线程,直接创建新线程,否则加入到workQueue,如果workQueue满了,则创建新worker。创建worker失败,则执行拒绝策略。

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();
        // 小于核心线程数,尝试创建新worker
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        // 如果pool是Running状态,则加入workQueue
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            // 如果当前线程数为0,则添加一个worker
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        // 加入workerQueue失败(队列已满等原因),则直接创建线程
        else if (!addWorker(command, false))
        	// 创建线程失败,则执行拒绝策略
            reject(command);
    }

2.2 addWorker

状态检查失败,返回false。worker调用start成功返回true,否则返回false。

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

			// 如果pool状态>=SHUTDOWN,并且rs不是SHUTDOWN或者firstTask不为null
			// 或者workerQueue为空。则返回false。
			// 如果是STOP或以上状态,不需要增加worker了,返回false。
			// 如果SHUTDOWN且firstTask不为null,不允许执行新任务,返回false。
			// 如果SHUTDOWN状态,那么允许添加工作线程去完成阻塞队列中的任务,如果队列为空,那么直接返回false。
            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;
				
			// workerCount+1
            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;
    }

2.3 addWorkerFailed

private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (w != null)
                workers.remove(w);
            decrementWorkerCount();
            tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }

2.4 tryTerminate

如果pool是可关闭(shutdown且队列为空或者stop)状态,则尝试清除工作线程并结束,如果工作线程数已经为0,则cas pool为TIDYING状态,直到成功为止。

final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            // pool正在执行或者已经TIDYING之上(有其他线程执行了,不用重复执行),
            // 或者SHUTDOWN状态下workerQueue还有待执行任务,直接退出
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            // 尝试清除空闲的工作线程,能获取到worker的锁,证明worker没有
            // 正在执行任务。不过极端情况下,可能worker刚获取到任务还没来
            // 得及获取锁,但是 interrupt不会影响任务执行,因为每次调用
            // task.run方法时,只要不是stop状态,都会调用interrupted(),
            // 清除interrupt标志。所以stop状态下,可能导致任务被interrupt。
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
            	// 工作线程清除完则设为TIDYING状态
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                    	// 调用完terminated方法,则设为TERMINATED状态
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

3 Worker

worker是一个工作线程,是pool中任务的实际执行者。负责执行被创建时分配的任务(firstTask),并在firstTask执行完之后,从workQueue拿取新任务,如果没有任务则根据条件选择等待workQueue中的新任务,或者直接结束该线程。
worker同时也是锁,继承了AQS,锁确保了worker执行任务的时候不会被terminate。terminate会打断阻塞地获取任务的核心线程(代码中取名为idle worker)

3.1 run

工作线程实际上及时调用pool的runWorker方法。

        public void run() {
            runWorker(this);
        }

3.1.1 runWorker

获取任务并执行,获取不到任务时(task==null),结束线程。

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        
        // 确保可以调用interruptIfStarted方法
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
        	// 如果firstTask还未执行或者能从workQueue获取新任务
        	//(核心线程可以阻塞获取任务,所以线程数小于核心线
        	// 程数时不会结束)则继续执行,否则结束该线程。
            while (task != null || (task = getTask()) != null) {
            	// worker执行完任务才会执行下一个任务,所以这里是为了
            	// 避免被interruptIdleWorkers打断正在执行的任务
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                // 如果线程池stop,那么当前任务由于已经从队列中取出,所以继续执行
                // 同时将线程设为interrupt,可以打断下次阻塞的从队列中获取任务,避免线程池无法关闭
                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();
                }
            }
            // 是否不正常结束,false表示正常结束
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

3.1.2 getTask

获取从阻塞队列任务,如果是核心线程且没有设置允许核心线程超时,则take阻塞地获取,否则poll限时获取。如果线程数超过最大线程数、获取超时了且删除线程不会导致阻塞队列中任务无法执行,则返回null。如果线程池被shutdown且队列空,或者stop也返回null。

private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

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

			// 如果SHUTDOWN且queue空,或者STOP则减少线程数,返回null会使
			// runWorker结束循环执行任务,最终执行processWorkerExit方法。
            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

			// 从workQueue获取任务时,是否有超时时间。
			// true限时获取任务
            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

			// 如果超过最大线程数或者限时获取任务时超时了,
			// 并且线程数超过1或者workqueue为空,则cas线程数-1,返回null
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
            	// 如果限时获取任务,则poll限时获取(获取不到任务线程就会结束),否则take阻塞获取,
            	// 这实现了核心线程阻塞获取任务,所以核心线程不会不被删除(allowCoreThreadTimeOut 为true除外)
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

3.1.3 processWorkerExit

线程退出操作。从workers中删除任务。如果是意外终止,则work数-1。
如果不是stop,且线程是意外终止或是工作线程数不足,则addWorker补充新线程。

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 {
        	// 将线程完成的任务加到pool的统计数据中
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

        tryTerminate();

        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
            	// 工作线程不足时(线程池中线程只超过核心线程数1个,但同时两个线程推出了,需要补一个回来),
            	// 需要补充线程,调用addWorker方法。
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值