在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. 不要在定时任务 / 异步里无限循环否则永远关不掉。

参考文献:豆包

相关推荐
studyForMokey2 小时前
【Android面试】Java专题 todo
android·java·面试
一只大袋鼠2 小时前
MyBatis 特性(三):缓存、延迟加载、注解开发
java·数据库·笔记·sql·缓存·mybatis
老毛肚2 小时前
Redis高级
java·数据库·redis
小Y._3 小时前
AQS同步器核心原理深度剖析
java·源码分析·juc·aqs
南棱笑笑生3 小时前
20260420给万象奥科的开发板HD-RK3576-PI适配瑞芯微原厂的Buildroot时使用ll命令
java·大数据·elasticsearch·rockchip
StockTV3 小时前
韩国市场API技术对接指南,涵盖实时行情、历史数据、指数信息、公司详情等功能
java·开发语言·python·php
缪懿3 小时前
javaEE:文件IO
java·java-ee
小Y._3 小时前
ConcurrentHashMap高效并发机制深度解析
java·并发·juc·concurrenthashmap
tang_jian_dong3 小时前
springboot + vue3 集成tianai.captcha验证码
java·spring boot·spring