我的编程空间,编程开发者的网络收藏夹
学习永远不晚

浅谈Java关闭线程池shutdown和shutdownNow的区别

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

浅谈Java关闭线程池shutdown和shutdownNow的区别

前言

本章分为两个议题

  • 如何正确关闭线程池
  • shutdown 和 shutdownNow 的区别

项目环境

  • jdk 1.8
  • github 地址:https://github.com/huajiexiewenfeng/java-concurrent
    • 本章模块:threadpool

1.线程池示例


public class ShutDownThreadPoolDemo {

    private ExecutorService service = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        new ShutDownThreadPoolDemo().executeTask();
    }

    public void executeTask() {
        for (int i = 0; i < 100; i++) {
            service.submit(() -> {
                System.out.println(Thread.currentThread().getName() + "->执行");
            });
        }
    }
}

执行结果

pool-1-thread-2->执行
pool-1-thread-3->执行
pool-1-thread-1->执行
pool-1-thread-4->执行
pool-1-thread-5->执行
pool-1-thread-6->执行
...

执行完成之后,主线程会一直阻塞,那么如何关闭线程池呢?本章介绍 5 种在 ThreadPoolExecutor 中涉及关闭线程池的方法,如下所示

  • void shutdown
  • boolean isShutdown
  • boolean isTerminated
  • boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException
  • List<Runnable> shutdownNow

2.shutdown

第一种方法叫作 shutdown(),它可以安全地关闭一个线程池,调用 shutdown() 方法之后线程池并不是立刻就被关闭,因为这时线程池中可能还有很多任务正在被执行,或是任务队列中有大量正在等待被执行的任务,调用 shutdown() 方法后线程池会在执行完正在执行的任务和队列中等待的任务后才彻底关闭。

调用 shutdown() 方法后如果还有新的任务被提交,线程池则会根据拒绝策略直接拒绝后续新提交的任务。

这段源码位置(jdk 1.8 版本)

java.util.concurrent.ThreadPoolExecutor#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();
        }
        // 核心线程已满,但是任务队列未满,添加到队列中
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            // 任务成功添加到队列以后,再次检查是否需要添加新的线程,因为已存在的线程可能被销毁了
            if (! isRunning(recheck) && remove(command))
                // 如果线程池处于非运行状态,并且把当前的任务从任务队列中移除成功,则拒绝该任务
                reject(command);
            else if (workerCountOf(recheck) == 0)
                // 如果之前的线程已经被销毁完,新建一个非核心线程
                addWorker(null, false);
        }
        // 核心线程池已满,队列已满,尝试创建一个非核心新的线程
        else if (!addWorker(command, false))
            // 如果创建新线程失败,说明线程池关闭或者线程池满了,拒绝任务
            reject(command);
    }

1373 行 if (! isRunning(recheck) && remove(command))
如果线程池被关闭,将当前的任务从任务队列中移除成功,并拒绝该任务

1378 行 else if (!addWorker(command, false))
如果创建新线程失败,说明线程池关闭或者线程池满了,拒绝任务。

3.isShutdown

第二个方法叫作 isShutdown(),它可以返回 true 或者 false 来判断线程池是否已经开始了关闭工作,也就是是否执行了 shutdown 或者 shutdownNow 方法。

这里需要注意,如果调用 isShutdown() 方法的返回的结果为 true 并不代表线程池此时已经彻底关闭了,这仅仅代表线程池开始了关闭的流程,也就是说,此时可能线程池中依然有线程在执行任务,队列里也可能有等待被执行的任务。

4.isTerminated

第三种方法叫作 isTerminated(),这个方法可以检测线程池是否真正“终结”了,这不仅代表线程池已关闭,同时代表线程池中的所有任务都已经都执行完毕了。

比如我们上面提到的情况,如果此时已经调用了 shutdown 方法,但是还有任务没有执行完,那么此时调用 isShutdown 方法返回的是 true,而 isTerminated 方法则会返回 false。

直到所有任务都执行完毕了,调用 isTerminated() 方法才会返回 true,这表示线程池已关闭并且线程池内部是空的,所有剩余的任务都执行完毕了。

5.awaitTermination

第四个方法叫作 awaitTermination(),它本身并不是用来关闭线程池的,而是主要用来判断线程池状态的。

比如我们给 awaitTermination 方法传入的参数是 10 秒,那么它就会陷入 10 秒钟的等待,直到发生以下三种情况之一:

  • 等待期间(包括进入等待状态之前)线程池已关闭并且所有已提交的任务(包括正在执行的和队列中等待的)都执行完毕,相当于线程池已经“终结”了,方法便会返回 true
  • 等待超时时间到后,第一种线程池“终结”的情况始终未发生,方法返回 false
  • 等待期间线程被中断,方法会抛出 InterruptedException 异常
  • 调用 awaitTermination 方法后当前线程会尝试等待一段指定的时间,如果在等待时间内,线程池已关闭并且内部的任务都执行完毕了,也就是说线程池真正“终结”了,那么方法就返回 true,否则超时返回 fasle。

6.shutdownNow

最后一个方法是 shutdownNow(),它和 shutdown() 的区别就是多了一个 Now,表示立刻关闭的意思,不推荐使用这一种方式关闭线程池。

在执行 shutdownNow 方法之后,首先会给所有线程池中的线程发送 interrupt 中断信号,尝试中断这些任务的执行,然后会将任务队列中正在等待的所有任务转移到一个 List 中并返回,我们可以根据返回的任务 List 来进行一些补救的操作,例如记录在案并在后期重试。

shutdownNow 源码如下:


    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;
    }

interruptWorkers

  • 让每一个已经启动的线程都中断,这样线程就可以在执行任务期间检测到中断信号并进行相应的处理,提前结束任务

7.shutdown 和 shutdownNow 的区别?

  • shutdown 会等待线程池中的任务执行完成之后关闭线程池,而 shutdownNow 会给所有线程发送中断信号,中断任务执行,然后关闭线程池
  • shutdown 没有返回值,而 shutdownNow 会返回关闭前任务队列中未执行的任务集合(List)

到此这篇关于浅谈Java关闭线程池shutdown和shutdownNow的区别的文章就介绍到这了,更多相关Java关闭线程池shutdown和shutdownNow内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

浅谈Java关闭线程池shutdown和shutdownNow的区别

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java线程池的几种实现方法和区别介绍实例详解

下面通过实例代码为大家介绍Java线程池的几种实现方法和区别:import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.ArrayList;
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录