java 优雅关闭线程池的方案

我们经常在项目中使用的线程池,但是是否关心过线程池的关闭呢,可能很多时候直接再项目中直接创建线程池让它一直运行当任务执行结束不在需要了也不去关闭,这其实是存在非常大的风险的,大量的线程常驻在后台对系统资源的占用是巨大的 ,甚至引发异常。所以在我们平时使用线程池时需要注意优雅的关闭,这样可以保证资源的管控。

在 Java 中和关闭线程池相关的方法主要有如下:

  • void shutdown()
  • List<Runnable> shutDownNow
  • boolean awaitTermination
  • boolean isShutDown
  • boolean isTerminated

对于这些方法有着不同的使用和作用,下面我们真的会这些不同的方法做详细的介绍。

ShutDown

shutDown 方法从字面意思我们可以看到是停止关闭的意思,我们先来看下面的一段代码,首先我们通过 ThreadPoolExecutor 来创建一个容量是10的无界线程池,与 FixedThreadPool 类似的,这里手动创建可以更好地理解线程池的创建。在后我们提交一千个任务执行,再执行 shutdown 方法进行暂停。

 public static void main(String[] args) throws InterruptedException {

  ExecutorService service = new ThreadPoolExecutor(
    10,
    10,
    0L,
    TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<>());

  for (int i = 0; i < 1000; i++) {
   service.submit(() ->{
    try {
     TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
     System.out.println("接受中断,不处理~~");
    }
    System.out.println("args = " + Arrays.deepToString(args)+ Thread.currentThread().getName());
   });
  }

  service.shutdown();
 }
  • 我们可以看到结果所以线程会正常执行结束后再关闭线程池,对于 ShutDown 而言它可以安全的停止一个线程池,它有几个关键点
  • ShutDown 会首先将线程设置成 SHUTDOWN 状态,然后中断所有没有正在运行的线程
  • 正在执行的线程和已经在队列中的线程并不会被中断,说白了就是使用shutDown 方法其实就是要等待所有任务正常全部结束以后才会关闭线程池
  • 调用 shutdown() 方法后如果还有新的任务被提交,线程池则会根据拒绝策略直接拒绝后续新提交的任务。

ShutDownNow

这个方法与上面方法相比较,直观就是 now ,即立即停止任务,
同样是上述案列,略作修改如下,

public static void main(String[] args) throws InterruptedException {

  ExecutorService service = new ThreadPoolExecutor(
    10,
    10,
    0L,
    TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<>(1000));

  for (int i = 0; i < 1000; i++) {
   service.submit(() ->{
    try {
     TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
     System.out.println("接受中断,结束线程~~");
     //这里响应中断
     return;
    }
    System.out.println("args = " + Arrays.deepToString(args)+ Thread.currentThread().getName());
   });
  }

  final List<Runnable> runnables = service.shutdownNow();
  System.out.println(runnables);
 }
  • 执行上述代码我们发现,当执行shutDownNow 方法后,会像全部正在运行的队列通知中断,正在运行的线程接收到中断信号后选择处理,而在队列中的全部取消执行转移到一个list队列中返回,如上述 List<Runnable> runnables ,这里记录了所有终止的线程

awaitTermination

  • 这个方法并不是用来关闭线程池的,首先我们看一下这个方法的定义:

boolean awaitTermination_(long timeout, TimeUnit unit)_

  • 可以看到这个方法有两个参数,timeout 表示等待的时间,unit 时间单位
  • 这个方法的作用是,调用后等待timeout时间后,反馈线程池的状态,
  • 等待期间(包括进入等待状态之前)线程池已关闭并且所有已提交的任务(包括正在执行的和队列中等待的)都执行完毕,相当于线程池已经“终结”了,方法便会返回 true;
  • 等待超时时间到后,第一种线程池“终结”的情况始终未发生,方法返回 false;
  • 等待期间线程被中断,方法会抛出 InterruptedException 异常。
  • 上面代码可以修改来测试,这里不再粘贴代码

isShutDown

  • isShutDown 方法正如名字,判断线程池是否停止,返回的是 Boolean 类型,如果已经开始停止线程池则返回 true 否则放回false
  • 当调用了shutDown 或shutDownNow 时之后,会返回 true 不过需要注意,这时候只是代表线程池关闭流程的开始,并不是说线程池已经停止了

isTerminated

  • 这个方法与上面的方法的区别就是这是正真检测线程池是否真的终结了
  • 这不仅代表线程池已关闭,同时代表线程池中的所有任务都已经都执行完毕了,因为在调用 shutdown方法之后,线程池会继续执行里面未完成的任务,包括正在执行的任务和在任务队列中等待的任务。
  • 如果调用了 shutdown 方法,但是有一个线程依然在执行任务,那么此时调用 isShutdown方法返回的是 true,而调用 isTerminated方法返回的便是 false,因为线程池中还有任务正在在被执行,线程池并没有真正“终结”。
  • 直到所有任务都执行完毕了,调用 isTerminated()方法才会返回 true,这表示线程池已关闭并且线程池内部是空的,所有剩余的任务都执行完毕了。

作者:AnonyStar

原文链接:https://www.cnblogs.com/i-code/p/14024845.html

以上就是java 优雅关闭线程池的方案的详细内容,更多关于Java 关闭线程池的资料请关注我们其它相关文章!

(0)

相关推荐

  • java线程池使用后到底要关闭吗

    线程池做什么 网络请求通常有两种形式: 第一种,请求不是很频繁,而且每次连接后会保持相当一段时间来读数据或者写数据,最后断开,如文件下载,网络流媒体等. 另一种形式是请求频繁,但是连接上以后读/写很少量的数据就断开连接.考虑到服务的并发问题,如果每个请求来到以后服务都为它启动一个线程,那么这对服务的资源可能会造成很大的浪费,特别是第二种情况. 因为通常情况下,创建线程是需要一定的耗时的,设这个时间为T1,而连接后读/写服务的时间为T2,当T1>>T2时,我们就应当考虑一种策略或者机制来控制,使

  • Java线程池用法实战案例分析

    本文实例讲述了Java线程池用法.分享给大家供大家参考,具体如下: 一 使用newSingleThreadExecutor创建一个只包含一个线程的线程池 1 代码 import java.util.concurrent.*; public class executorDemo { public static void main( String[] args ) { ExecutorService executor = Executors.newSingleThreadExecutor(); ex

  • Java判断线程池线程是否执行完毕

    在使用多线程的时候有时候我们会使用 java.util.concurrent.Executors的线程池,当多个线程异步执行的时候,我们往往不好判断是否线程池中所有的子线程都已经执行完毕,但有时候这种判断却很有用,例如我有个方法的功能是往一个文件异步地写入内容,我需要在所有的子线程写入完毕后在文件末尾写"---END---"及关闭文件流等,这个时候我就需要某个标志位可以告诉我是否线程池中所有的子线程都已经执行完毕,我使用这种方式来判断. public class MySemaphore

  • Java手动配置线程池过程详解

    线程池中,常见有涉及到的: ExecutorService executorService = Executors.newSingleThreadExecutor(); ExecutorService executorService1 = Executors.newCachedThreadPool(); ExecutorService executorService2 = Executors.newFixedThreadPool(3); 关于Executors和ExecutorService从记

  • Java线程池的拒绝策略实现详解

    一.简介 jdk1.5 版本新增了JUC并发编程包,大大的简化了传统的多线程开发. Java线程池,是典型的池化思想的产物,类似的还有数据库的连接池.redis的连接池等.池化思想,就是在初始的时候去申请资源,创建一批可使用的连接,这样在使用的时候,就不必再进行创建连接信息的开销了.举个生活中鲜明的例子,在去著名洋快餐某基或者某劳的时候,配餐人员是字节从一个中间的保温箱里面直接取,然后打包就好了.不用再临时的来了一个单子,又要去拿原材料,又要去进行加工.效率明显的就是提高了很多. 既然是池子,那

  • java中常见的6种线程池示例详解

    之前我们介绍了线程池的四种拒绝策略,了解了线程池参数的含义,那么今天我们来聊聊Java 中常见的几种线程池,以及在jdk7 加入的 ForkJoin 新型线程池 首先我们列出Java 中的六种线程池如下 线程池名称 描述 FixedThreadPool 核心线程数与最大线程数相同 SingleThreadExecutor 一个线程的线程池 CachedThreadPool 核心线程为0,最大线程数为Integer. MAX_VALUE ScheduledThreadPool 指定核心线程数的定时

  • java ThreadPool线程池的使用,线程池工具类用法说明

    实际上java已经提供线程池的实现 ExecutorService. 为了更方便的使用和管理.这里提供一个线程池工具类,方便大家的使用. 直接看看代码: 使用 public static void main(String[] args) { //实例化一个固定数目的线程池.具体参考类的构造方法 ThreadPool threadPool=new ThreadPool(ThreadPool.FixedThread,5); //线程池执行线程 threadPool.execute(new Runna

  • Java线程池ThreadPoolExecutor原理及使用实例

    引导 要求:线程资源必须通过线程池提供,不允许在应用自行显式创建线程: 说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题.如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗内存或者"过度切换"的问题. 线程池介绍线程池概述   线程池,顾名思义是一个放着线程的池子,这个池子的线程主要是用来执行任务的.当用户提交任务时,线程池会创建线程去执行任务,若任务超过了核心线程数的时候,会在一个任务队列里进行排队等待,这个详细流程,我们会后面细

  • JAVA 自定义线程池的最大线程数设置方法

    一:CPU密集型: 定义:CPU密集型也是指计算密集型,大部分时间用来做计算逻辑判断等CPU动作的程序称为CPU密集型任务.该类型的任务需要进行大量的计算,主要消耗CPU资源.  这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数. 特点:    01:CPU 使用率较高(也就是经常计算一些复杂的运算,逻辑处理等情况)非常多的情况下使用    02:针对单台机

  • Java线程池运行状态监控实现解析

    在实际开发过程中,在线程池使用过程中可能会遇到各方面的故障,如线程池阻塞,无法提交新任务等. 如果你想监控某一个线程池的执行状态,线程池执行类 ThreadPoolExecutor 也给出了相关的 API, 能实时获取线程池的当前活动线程数.正在排队中的线程数.已经执行完成的线程数.总线程数等. 总线程数 = 排队线程数 + 活动线程数 + 执行完成的线程数. 线程池使用示例: private static ExecutorService es = new ThreadPoolExecutor(

  • JAVA 创建线程池的注意事项

    1.创建线程或线程池时请指定有意义的线程名称,方便出错时回溯.创建线程池的时候请使用带ThreadFactory的构造函数,并且提供自定义ThreadFactory实现或者使用第三方实现. ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() .setNameFormat("demo-pool-%d").build(); ExecutorService singleThreadPool = new ThreadPoo

  • java 定时器线程池(ScheduledThreadPoolExecutor)的实现

    前言 定时器线程池提供了定时执行任务的能力,即可以延迟执行,可以周期性执行.但定时器线程池也还是线程池,最底层实现还是ThreadPoolExecutor,可以参考我的另外一篇文章多线程–精通ThreadPoolExecutor. 特点说明 1.构造函数 public ScheduledThreadPoolExecutor(int corePoolSize) { // 对于其他几个参数在ThreadPoolExecutor中都已经详细分析过了,所以这里,将不再展开 // 这里我们可以看到调用基类

  • Java 线程状态和等待唤醒机制和线程池的实现

    1.概念 线程一共有6中状态,相互之间可以互相转换. 等待唤醒案例(线程之间的通信) 实现: 等待唤醒案例:线程之间的通信 创建一个顾客线程(消费者):告知老板要的包子的种类和数量,调用wait方法,放弃cpu的执行,进入到WAITING状态(无限等待) 创建一个老板线程(生产者):花了5秒做包子,做好包子之后,调用notify方法,唤醒顾客吃包子 注意: 顾客和老板线程必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行 同步使用的锁对象必须保证唯一 只有锁对象才能调用wait和noti

随机推荐