在tomcat应用里添加了一个线程池对象,向这个线程池发送任务,让其执行。 我希望在tomcat停机时,能等待线程池里的任务执行完了再停机,要如何实现?

核心思路

  1. 项目启动时创建全局单例线程池
  2. 实现 ServletContextListener
  3. 停机时调用线程池的优雅关闭方法 :
    • shutdown()
    • awaitTermination(...) 等待任务执行完
  4. 超时未关闭则强制关闭 shutdownNow()

完整实现代码

1. 线程池单例(建议放在工具类)

java 复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TaskPool {

    // 全局唯一线程池
    private static final ExecutorService EXECUTOR = new ThreadPoolExecutor(
            5,
            10,
            60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100)
    );

    public static ExecutorService getExecutor() {
        return EXECUTOR;
    }
}
  1. 编写监听器(关键)
java 复制代码
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

@WebListener // 让 Tomcat 自动识别
public class ThreadPoolShutdownListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // 应用启动时可做初始化
        System.out.println("Tomcat 应用启动");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("Tomcat 停机,开始关闭线程池...");

        ExecutorService executor = TaskPool.getExecutor();

        // 1. 拒绝新任务
        executor.shutdown();

        try {
            // 2. 等待已提交任务执行完毕(例如等30秒)
            if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                System.err.println("线程池超时未关闭,强制关闭");
                // 3. 超时则强制关闭
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            System.err.println("关闭线程池被中断");
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }

        System.out.println("线程池已安全关闭");
    }
}
  1. 如果不用 @WebListener,就在 web.xml 配置
XML 复制代码
<listener>
    <listener-class>com.xxx.xxx.ThreadPoolShutdownListener</listener-class>
</listener>

为什么这样能保证 Tomcat 等任务执行完?

  • Tomcat 停止时会按顺序调用所有 ServletContextListener 的 contextDestroyed
  • awaitTermination(30, SECONDS) 会阻塞当前线程 ,直到:
    • 所有任务执行完
    • 或超时
  • 阻塞期间 Tomcat 不会继续销毁 Filter、Servlet,实现等待效果

重要注意点

  1. 不要用 Executors.newFixedThreadPool 队列无界,可能堆积太多任务导致停机很久。
  2. awaitTermination 时间要合理 一般 10~60 秒,根据你的任务耗时设置。
  3. 你的任务最好能响应中断 否则 shutdownNow() 也杀不掉,会一直卡到超时。
  4. 不要在定时任务 / 异步里无限循环否则永远关不掉。

参考文献:豆包

相关推荐
用户1305180712152 小时前
JDBC学习DAY2:从Statement到PreparedStatement
java
蛋蛋的就会顺顺的2 小时前
hot100——矩阵
java·数据结构·算法·leetcode·力扣
周杰偷奶茶2 小时前
【Java】数组的定义和使用(附管理系统实战案例)
java·开发语言
橙子圆1233 小时前
JUC之集合类不安全
java·开发语言
谢亮_vipxieliang4 小时前
Stream API 不是银弹:常见坑与性能建议
java·开发语言
源码宝4 小时前
Web‑PACS 云影像源码|Java+Vue3 医院影像管理系统完整方案
java·源码·影像pacs·成品源码·医院影像系统
ShineWinsu4 小时前
对于Redis:string类型的解析
java·c++·redis·分布式·缓存·面试·string
三8446 小时前
Fastjson 漏洞 · 02 · autoType 机制与 checkAutoType
java·fastjson
无限码力7 小时前
小红书笔试真题 9.17 - 待发热度重排(C++/Py/Java /Js/Go)
java·小红书·小红书笔试真题·小红书技术岗笔试真题