首页 > 编程语言 >Java优雅关闭线程池

Java优雅关闭线程池

时间:2024-04-28 18:22:06浏览次数:23  
标签:Java shutdown 优雅 任务 线程 关闭 executor logger

一、背景:

线程池中有任务正在执行,此时需要关闭或重启应用,池中的任务如何处理,需要考虑任务的损失、关闭速度两个方面考虑。

推荐使用Spring提供的线程池:ThreadPoolTaskExecutor,让Spring帮我们管理线程池的生命周期,初始化、监控、扩展、关闭。
特别在应用关闭、重启时能实现优雅关闭线程池,以使我们的损失降到最低;但前提是配置合理的初始化参数。

二、原理:

在Spring中如果一个Bean类,实现了Disposable接口,并实现了其destroy方法。当Spring在销毁这个类的Bean时,就会执行这个destroy方法。通常destroy方法用于执行一些善后工作,比如资源回收、关闭数据库连接、关闭线程池、回收文件资源等。
Spring提供的线程池:ThreadPoolTaskExecutor类的父类ExecutorConfigurationSupport正好实现了DisposableBean接口:

/**
	 * Calls {@code shutdown} when the BeanFactory destroys
	 * the task executor instance.
	 * @see #shutdown()
	 */
@Override
public void destroy() {
  shutdown();
}

/**
	 * Perform a shutdown on the underlying ExecutorService.
	 * @see java.util.concurrent.ExecutorService#shutdown()
	 * @see java.util.concurrent.ExecutorService#shutdownNow()
	 */
public void shutdown() {
  if (logger.isInfoEnabled()) {
    logger.info("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
  }
  if (this.executor != null) {
    // 是否等待任务全部执行完毕再关闭的开关
    if (this.waitForTasksToCompleteOnShutdown) {
      // 关闭JDK线程池
      this.executor.shutdown();//非阻塞
    }
    else {
      //shutdownNow()的作用:
      //1.不再接收新任务
      //2.清空任务队列,并返回等待执行的任务,并取消这些任务(要支持取消,就必须实现RunneableFuture接口的cancel方法)
      //3.立即中断正在执行的任务(能中断就中断,否则就让其执行完毕)
      for (Runnable remainingTask : this.executor.shutdownNow()//非阻塞) {
        cancelRemainingTask(remainingTask);
      }
    }
    awaitTerminationIfNecessary(this.executor);
  }
}

/**
	 * Wait for the executor to terminate, according to the value of the
	 * {@link #setAwaitTerminationSeconds "awaitTerminationSeconds"} property.
	 */
private void awaitTerminationIfNecessary(ExecutorService executor) {
  if (this.awaitTerminationMillis > 0) {
    try {
      //用户在定义线程池时,需要给定一个优雅关闭的超时时间,一定要拿捏适度,否则就会
      if (!executor.awaitTermination(this.awaitTerminationMillis, TimeUnit.MILLISECONDS)) {
        if (logger.isWarnEnabled()) {
          logger.warn("Timed out while waiting for executor" +
                      (this.beanName != null ? " '" + this.beanName + "'" : "") + " to terminate");
        }
      }
    }
    catch (InterruptedException ex) {
      if (logger.isWarnEnabled()) {
        logger.warn("Interrupted while waiting for executor" +
                    (this.beanName != null ? " '" + this.beanName + "'" : "") + " to terminate");
      }
      Thread.currentThread().interrupt();
    }
  }
}

实践策略:

  1. 任务优先:保证任务能执行完毕

1.waitForTasksToCompleteOnShutdown设为true。
2.awaitTerminationMillis超时时间设置长一点。
3.任务队列尽量小一点(以提高关闭速度)。

  1. 速度优先:尽可能快的关闭线程池

1.waitForTasksToCompleteOnShutdown设为false。
2.假如单个任务比较耗时,需要将任务定义为“中断友好”。
3.实现RunneableFuture接口的cancel方法。
4.awaitTerminationMillis设得短一点,即便任务取消失败,也能利用超时机制关闭线程池。
5.任务队列容量小一些,以减小损失。

强制杀死应用进程的情形,Spring也帮不上忙,此时要做到:

1.做好任务执行记录,方便从断点继续执行。
2.尽量保证任务的幂等性,即便全部重执行,也不会引入副作用。

标签:Java,shutdown,优雅,任务,线程,关闭,executor,logger
From: https://www.cnblogs.com/JaxYoun/p/18164265

相关文章

  • [羊城杯 2020]A Piece Of Java
    发现我java基础不牢,做点老题,多思考思考。打开jar包先看到MainController.class:/index路由设置一个cookie,访问的时候没设置cookie就会重定向到hello路由。这个cookie也就是username和password进行serialize来的,看到下面序列化和反序列化的方法:序列化没什么好说的,反序列化这里......
  • Redis单线程,为什么速度快
    Redis是单线程的,但是为什么还那么快完全基于内存的,C语言编写采用单线程,避免不必要的上下文切换可竞争条件使用多路IO复用模型,非阻塞IO例如:bgsave和bgrewriteaof都是在后台执行操作,不影响主线程的正常使用,不会产生阻塞解释一下多路IO复用模型?多路IO复用模型是指利用......
  • JavaScript流程控制语句
    JavaScript流程控制语句在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。所以,我们必须清楚每条语句的执行流程。而且,很多时候我们要通过控制语句的执行顺序来实现我们想要的业务逻辑和功能。分类一般我们把流程控制语句分为以下三类顺序结构选择结......
  • java ini配置工具类 -复制工具类即可使用
    package这里写你工具类包存放的地址importjava.io.BufferedReader;importjava.io.BufferedWriter;importjava.io.FileReader;importjava.io.FileWriter;importjava.io.IOException;importjava.net.URLDecoder;importjava.util.regex.Matcher;importjava.util.regex.Patt......
  • Java学习之Jackson
    介绍两种Java主流的转化工具Jackson和FastJson,一般项目中建议只选其中一种。Jackson1.将JSON字符串转成Java对象:readvalue方法第一个参数是Json字符串,第二个参数是将要转化类的类型ObjectMapperobjectMapper=newObjectMapper();MatchMatch=objectMapper.readValue(jsonStr......
  • 第十五届蓝桥杯 网络安全赛道 ezjava
    1.前言前一秒还在robots.txt找flag,下一秒就java内存马了,还不出网,这很......
  • Java:实验四 Java图形界面与事件处理(头歌)
    importjavax.swing.*;importjava.awt.*;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjava.awt.event.ItemEvent;importjava.awt.event.ItemListener;/***CreatedbyIntelliJIDEA.**@Author:*@create:2023/03/2......
  • 揭秘JavaScript数据世界:一文通晓基本类型和引用类型的精髓!
    在编程的世界里,数据是构建一切的基础。就像建筑师需要了解不同材料的强度和特性一样,程序员也必须熟悉各种数据类型。今天,我们就来深入探讨JavaScript中的数据类型,看看它们如何塑造我们的代码世界。一、JavaScript数据类型简介数据类型是计算机语言的基础知识,数据类型广泛用于变......
  • 线程池
    线程池1.线程池概念 2.标准库线程池(面试考点) 总结:  3.工厂类创建线程池和基本使用查看代码importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;classTest{publicstaticvoidmain(String[]args){......
  • Java面试题:你知道Spring的IOC吗?那么,它为什么这么重要呢?
    Spring的IOC(控制反转)是一种设计模式,它允许开发者将对象的创建和管理交给Spring框架来完成。在Spring中,IOC允许开发者将对象依赖关系从代码中分离出来,从而使代码更加灵活、可重用和易于管理。IoC全称InverseofControl(反向控制或控制反转)。在类和类之间存在控制权,控制权指的是......