返回顶部
首页 > 资讯 > 后端开发 > Python >浅谈Java关闭线程池shutdown和shutdownNow的区别
  • 360
分享到

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

2024-04-02 19:04:59 360人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录前言项目环境1.线程池示例2.shutdown3.isshutdown4.isTerminated5.awaitTermination6.shutdownNow7.shutdow

前言

本章分为两个议题

  • 如何正确关闭线程
  • 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内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 浅谈Java关闭线程池shutdown和shutdownNow的区别

本文链接: https://lsjlt.com/news/136737.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 浅谈Java关闭线程池shutdown和shutdownNow的区别
    目录前言项目环境1.线程池示例2.shutdown3.isShutdown4.isTerminated5.awaitTermination6.shutdownNow7.shutdow...
    99+
    2024-04-02
  • 浅谈Android 的线程和线程池的使用
    Android 的线程和线程池从用途上分,线程分为主线程和子线程;主线程主要处理和界面相关的事情,子线程则往往用于耗时操作。主线程和子线程主线程是指进程所拥有的线程。Android 中主线程交 UI 线程,主要作用是运行四大组件以及处理它们...
    99+
    2023-05-30
    android 线程池 roi
  • 浅谈Java中Lock和Synchronized的区别
    目录1. 从功能角度来看2. 从特性来看3. 从性能方面来看1. 从功能角度来看 Lock和Synchronized都是java中去用来解决线程安全问题的一个工具 2. 从特性来看 ...
    99+
    2024-04-02
  • 浅谈Java线程池的7大核心参数
    目录前言一、线程池的创建及重要参数二、ThreadPoolExecutor中重要的几个参数详解三、workQueue队列(阻塞队列)四、常见的几种自动创建线程池方式五、线程池实现线程...
    99+
    2024-04-02
  • 浅谈Java中static和非static的区别
    关于static和非static变量的区别 static 修饰的变量称为类变量或全局变量或成员变量,在类被加载的时候成员变量即被初始化,与类关联,只要类存在,static变量就存在。非static修饰的成员变量是在对象new出来的时候划分存...
    99+
    2023-05-31
    java static ava
  • 浅谈spring和spring MVC的区别与关系
    spring是一个开源框架,功能主要是依赖注入和控制反转。依赖注入有三种形式1、构造注入(bytype)2、setter注入3、接口注入(byname) 而控制反转则主要是起到操控作用,把对象的创建,初始化,销毁交给spring容器来处理。...
    99+
    2023-05-31
    spring springmvc sprin
  • 【Java】如何优雅的关闭线程池
    文章目录 背景一、线程中断 interrupt二、线程池的关闭 shutdown 方法2.1、第一步:advanceRunState(SHUTDOWN) 把线程池置为 SHUTDOWN2.2、...
    99+
    2023-09-21
    java 开发语言
  • 浅谈Java中IO和NIO的本质和区别
    目录IO的本质DMA和虚拟地址空间IO的分类IO和NIO的区别IO的本质 IO的作用就是从外部系统读取数据到java程序中,或者把java程序中输出的数据写回到外部系统。这里的外部系...
    99+
    2024-04-02
  • 浅谈java中的重载和重写的区别
    目录1.重载小结:2.重写小结:总结1.重载 重载指在一个类中,具有多个相同名称的方法,他们的参数列表却不相同 (参数类型不同、参数个数不同甚至是参数顺序不同) 重载对返回类型没有要...
    99+
    2024-04-02
  • Java中线程组ThreadGroup与线程池的区别及示例
    目录线程组概念理解线程组实践线程组和线程池的区别线程组概念理解 在java的多线程处理中有线程组ThreadGroup的概念,ThreadGroup是为了方便线程管理出现了,可以统一...
    99+
    2023-05-19
    Java 线程组 Java ThreadGroup
  • Java守护线程和用户线程的区别
    目录守护线程定义创建守护线程将线程池设置为守护线程守护线程 VS 用户线程用户线程守护线程守护线程注意事项总结前言: 在 Java 语言中,线程分为两类:用户线程和守护线程,默认情况...
    99+
    2024-04-02
  • java中线程池最实用的创建与关闭指南
    目录前言线程池创建 只需要执行shutdown就可以优雅关闭 执行shutdownNow关闭的测试 总结前言 在日常的开发工作当中,线程池往往承载着一个应用中最重要的业务逻辑,因此我...
    99+
    2024-04-02
  • 浅谈JAVA 线程状态中可能存在的一些误区
    BLOCKED 和 WAITING 的区别 BLOCKED 和 WAITING 两种状态从结果上来看,都是线程暂停,不会占用 CPU 资源,不过还是有一些区别的 BLOCKED ...
    99+
    2024-04-02
  • 浅谈Java异常的Exception e中的egetMessage()和toString()方法的区别
    Exception e中e的getMessage()和toString()方法的区别:示例代码1:public class TestInfo { private static String str =null; public stati...
    99+
    2023-05-31
    egetmessage tostring java
  • Java线程池的几种实现方法和区别介绍实例详解
    下面通过实例代码为大家介绍Java线程池的几种实现方法和区别:import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.ArrayList;...
    99+
    2023-05-31
    java 线程池 ava
  • Java之进程和线程的区别是什么
    这篇文章主要介绍“Java之进程和线程的区别是什么”,在日常操作中,相信很多人在Java之进程和线程的区别是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java之进程和线程的区别是什么”的疑惑有所帮助!...
    99+
    2023-07-05
  • java线程sleep和wait的区别有哪些
    Java中的线程sleep和wait方法有以下区别:1. 调用wait方法的线程会放弃自己的锁,并进入等待状态,直到其他线程调用相同...
    99+
    2023-09-25
    java
  • Java线程和操作系统的线程有什么区别
    这篇文章主要介绍了Java线程和操作系统的线程有什么区别,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1. 用户空间和内核空间关于内核态和用户态我们在 了解操作系统的那些事儿...
    99+
    2023-06-15
  • Java中守护线程和用户线程的区别有哪些
    这篇文章主要介绍Java中守护线程和用户线程的区别有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!常用的java框架有哪些1.SpringMVC,Spring Web MVC是一种基于Java的实现了Web MV...
    99+
    2023-06-14
  • 3种Java创建线程的方式和区别
    在java中如何创建线程?下面本篇文章给大家介绍3种创建线程的方式以及区别。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。在java中如果要创建线程的话,一般有3种方法:继承Thread类;实现Runnable接口;使用C...
    99+
    2017-09-19
    java入门 Java 线程
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作