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

参考文献:豆包

相关推荐
plainGeekDev7 分钟前
RecyclerView.Adapter → ListAdapter
java·kotlin·gradle
J2虾虾18 分钟前
Spring AI Alibaba - 人工介入(Human-in-the-Loop)
java·人工智能·spring
Old Uncle Tom38 分钟前
Harness Engineering 综述
java·开发语言·数据库
星原望野41 分钟前
JAVA:策略模式的实战使用
java·开发语言·策略模式
LJianK142 分钟前
java多态
java·开发语言·python
z落落1 小时前
C# 构造函数(无参/有参/重载/this)+析构函数(终结器)|GC 垃圾回收
java·开发语言·c#
武子康1 小时前
Java-12 深入浅出 MyBatis 二级缓存详解:跨 SqlSession 共享与失效机制
java·后端
考虑考虑1 小时前
JDK9中的Set.of()使用注意
java·后端·java ee
plainGeekDev1 小时前
findViewById → ViewBinding
java·kotlin·gradle
yz_aiks1 小时前
IDEA终端配置oh-my-zsh实战:安装、插件与日常使用技巧
java·ide·intellij-idea