线程池(三)

概述

这里聊几个ThreadPoolExecutor涉及到的两个关键的方法。
1. void shutdown()
2. List shutdownNow()

shutdown()

执行线程池的关闭操作,此时不会接收新的任务,但是会执行完任务队列的任务。

public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();// 校验权限,不重要
            advanceRunState(SHUTDOWN);// CAS设置线程池状态为SHUTDOWN
            interruptIdleWorkers();//中断空闲线程
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }

中断空闲线程

private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
                if (!t.isInterrupted() && w.tryLock()) {// 判断是否是空闲线程。w.tryLock()如果拿不到锁,说明线程正在执行,因为runWorker方法执行run的时候要先w.lock获得锁,这时候这里是获取不到锁的。
                    try {
                        t.interrupt();// 执行线程中断,runWorker中while循环中等待从队列获取的线程会退出来,completedAbruptly = false;执行processWorkerExit(w, completedAbruptly)。
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }

中止线程池里的所有线程

final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;// 如果线程池处于running或任务队列不为空,不做操作
            if (workerCountOf(c) != 0) { // 如果有线程在执行任务
                interruptIdleWorkers(ONLY_ONE);// 只中断一个线程。下面的操作交给其他线程执行。这里保证只有一个线程往下面走。
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();// 执行中断的钩子方法
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));// 设置线程池状态为中止
                        termination.signalAll();// 唤醒等待在condition上的所有线程
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

等待线程池线程中断完毕

public boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException {
        long nanos = unit.toNanos(timeout);
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (;;) {
                if (runStateAtLeast(ctl.get(), TERMINATED))
                    return true;
                if (nanos <= 0)
                    return false;
                nanos = termination.awaitNanos(nanos);
            }
        } finally {
            mainLock.unlock();
        }
    }

shutdownNow()

public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(STOP);// 设置线程池状态为stop
            interruptWorkers();//中止所有线程
            tasks = drainQueue();//将workQueue的所有未执行任务拷贝给List tasks返回
        } finally {
            mainLock.unlock();
        }
        tryTerminate();// 尝试中止线程
        return tasks;// 返回未执行的任务
    }

总结

线程池怎么保证内部一定有一定数量的线程在运行?
注:由于线程池逻辑复杂,我们只是分析最普遍的逻辑。

ThreadPoolExecutor举例子!
重点方法在runWorker(Worker w)方法的while (task != null || (task = getTask()) != null)这个while循环内。

  1. 如果是正常通过execute(runnable)进来的task != null成立,执行task.run()方法,结束后回到while (task != null || (task = getTask()) != null),此时task==null,方法阻塞在(task = getTask()) != null,从阻塞队列拿任务
  2. (task = getTask()) != null方法支持超时机制获取队列任务。如果当前正在执行的任务数或者核心线程允许超时,boolean timed = allowCoreThreadTimeOut || wc > corePoolSize为true,否则为false
  3. 接着从队列获取任务Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();,如果拿到了,就返回任务r,否则返回null,阻塞方法从while (task != null || (task = getTask()) != null)返回
  4. (task = getTask()) != null成立,执行任务的run方法,正常结束后接着阻塞在while (task != null || (task = getTask()) != null)
  5. (task = getTask()) != null不成立,退出while (task != null || (task = getTask()) != null)循环,此时completedAbruptly = false;w == null,执行processWorkerExit(w, completedAbruptly)方法
  6. 进入processWorkerExit(w, completedAbruptly)方法后,执行tryTerminate()方法,由于isRunning(c)为true,直接返回,线程从tryTerminate()方法返回,继续往下执行
  7. if (runStateLessThan(c, STOP))if (!completedAbruptly)同时成立,如果当前正在执行的任务数量大于等于允许的最小线程数量,即if (workerCountOf(c) >= min)成立,线程从processWorkerExit(w, completedAbruptly)退出,线程死亡。如果当前正在执行的任务数量小于允许的最小线程数量,即if (workerCountOf(c) >= min)不成立,执行addWorker(null, false)方法,使用线程工厂重新创建一个线程,重新进入runWorker(Worker w)方法,阻塞在while (task != null || (task = getTask()) != null),重复步骤1。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值