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

核心思路

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

完整实现代码

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

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;
    }
}

2. 编写监听器(关键)

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("线程池已安全关闭");
    }
}

3. 如果不用 @WebListener,就在 web.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. 不要在定时任务 / 异步里无限循环 否则永远关不掉。

参考文献:豆包

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值