Java线程池---ShutDown以及ShutDownNow解析

ShutDown函数的注释:

/**
 * Initiates an orderly shutdown in which previously submitted
 * tasks are executed, but no new tasks will be accepted.
 * Invocation has no additional effect if already shut down.
 *
 * <p>This method does not wait for previously submitted tasks to
 * complete execution.  Use {@link #awaitTermination awaitTermination}
 * to do that.
 *
 * @throws SecurityException {@inheritDoc}
 */

初始化一个有序的关闭,之前提交的任务都会被执行,但是新提交的任务则不会被允许放入任务队列中。如果之前被调用过了的话,那么再次调用也没什么用。这个方法不会等待之前提交的任务完成执行,如果希望的话,则需要调用awaitTermiante方法。

该函数的代码为:

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(SHUTDOWN);
        interruptIdleWorkers();
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
}
  1. 获取线程池的锁,然后调用checkShutdownAccess方法检查每一个线程池的线程是否有可以ShutDown的权限。
  2. 调用advanceRunState函数通过自旋的CAS操作来将ctl中的状态变为SHUTDOWN
  3. 调用interruptIdleWorkers方法,将所有Idle状态的线程都调用interrupt方法,中断线程。而判断idle状态使用Worker中的ReentrantLock来调用tryLock尝试加锁,看Worker线程是否已经获取了锁,如果Worker的锁已经被加了的话,那么tryLock返回的就是false。
  4. 通过onShutDown()方法告知子类,线程池要处于ShutDown状态了。
  5. 解锁完后,调用tryTermiante的方法尝试终止线程池。

ShutDownNow方法和ShutDown方法差不多。具体看下面的代码

 public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(STOP);
        interruptWorkers();
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

这两个方法的区别有:

  1. shutDownNow方法会返回未完成的任务队列中的任务列表
  2. advanceRunState方法中传入的是STOP,而不是SHUTDOWN。

而在tryTermiante方法中:

 final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        if (workerCountOf(c) != 0) { // Eligible to terminate
            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();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}
  1. 判断当前线程池是否正在运行,或者当前线程池的状态比TIDYING(整理中)要大(也就是处于TIDYING或者TERMINATED状态),或者当前线程状态处于SHUTDOWN并且任务队列不为空的话,那么就直接return
  2. 如果当前的WorkerCount不为0,那么就会调用interruptedIdleWorkers(true),并且返回
  3. 通过CAS操作将ctl设置成TIDYING,如果设置成功之后就会调用terminated方法, 告知子类,要终止了,终止完之后,就会将ctl的状态设置成TERMINATED,以及workerCount为0。

PS:在tryTerminate函数中,会有判断如果是SHUTDOWN状态的话,那么就需要判断任务队列是否为空,如果为空的话,那么就会接着往下走,如果任务队列不为空的话,那么说明还有任务没有执行完,直接返回了。在最后一个Worker运行结束后,调用的processWorkerExit函数中还会调用tryTerminate,所以到那时候,才是真正的结束。 而在tryTeminate后的一句if(workerCountOf(c)!=0)成立的话,也就是说明任务队列空了,但是Worker还有多的,那么就将最多一个处于IDLE状态的Worker中断。这一段没有太明白具体要干什么。不理解。

至此,整个线程池就完全退出了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java编程技术

FutureTask 原理

如上代码主线程会在futureTask.get()出阻塞直到task任务执行完毕,并且会返回结果。

10510
来自专栏码匠的流水账

resilience4j小试牛刀

resilience4j是一款受hystrix启发的容错组件,提供了如下几款核心组件:

84010
来自专栏wannshan(javaer,RPC)

JDK7 ThreadPoolExecutor execute(Runnable command) 方法解析

/** * 通过这个方法提交的线程,将在新的线程,或者已有的(线程池)线程中执行 * * * If the task ...

54460
来自专栏编码小白

ofbiz实体引擎(一) 获取Delegator

public abstract class DelegatorFactory implements Factory<Delegator, String> { ...

39750
来自专栏函数式编程语言及工具

浅谈Slick(2)- Slick101:第一个动手尝试的项目

   看完Slick官方网站上关于Slick3.1.1技术文档后决定开始动手建一个项目来尝试一下Slick功能的具体使用方法。我把这个过程中的一些了解和想法记录...

28790
来自专栏会跳舞的机器人

java并发编程的艺术第十章——Executor框架

Executor框架的主要成员:ThreadPoolExecutor、ScheduledThreadPoolExecutor、Future接口、Runnable...

12520
来自专栏函数式编程语言及工具

浅谈Slick(4)- Slick301:我的Slick开发项目设置

  前面几篇介绍里尝试了一些Slick的功能和使用方式,看来基本可以满足用scala语言进行数据库操作编程的要求,而且有些代码可以通过函数式编程模式来实现。我想...

238100
来自专栏码匠的流水账

java8 parallelStream性能测试

默认是Runtime.getRuntime().availableProcessors() - 1,这里为7

39620
来自专栏编码小白

tomcat请求处理分析(六)servlet的处理过程

1.1.1.1  servlet的解析过程 servlet的解析分为两步实现,第一个是匹配到对应的Wrapper,第二个是加载对应的servlet并进行数据,这...

75670
来自专栏大大的微笑

web项目定时执行任务

首先写了个servlet 例如 package com.uap.weixin.service; import java.text.DateFormat; im...

24560

扫码关注云+社区

领取腾讯云代金券