首页 文章

关闭tomcat时停止预定计时器[重复]

提问于
浏览
21

这个问题在这里已有答案:

我有一个部署到Tomcat服务器的WAR文件,其中一个类将在启动时调用,然后init()方法将安排一个计时器每5小时触发一次以执行某些任务 .

我的init()代码如下所示:

public void init()
{
    TimerTask parserTimerTask = new TimerTask() {

        @Override
        public void run() {
            XmlParser.parsePage();
        }
    };

    Timer parserTimer = new Timer();
    parserTimer.scheduleAtFixedRate(parserTimerTask, 0, PERIOD);
}

我的应用程序运行没有问题,但当我使用 /etc/init.d/tomcat7 stop 关闭Tomcat时,我检查日志(catalina.out)它有一个这样的条目:

SEVERE: The web application [/MyApplication] appears to have started a thread named [Timer-0] but has failed to stop it. This is very likely to create a memory leak.

我明白这是由我安排计时器引起的,但我的问题是:

  • 我没有将 setDeamon 设置为true,所以定时器不应该阻止Tomcat关闭,而不是保持运行?

  • 我可以在我的应用程序中检测Tomcat是否会关闭并取消我的计时器?

  • 我可以使用哪些其他解决方案来解决这个问题?

谢谢!

UPDATE

我根据一些搜索和DaveHowes的答案将我的代码更改为以下内容 .

Timer parserTimer;
TimerTask parserTimerTask;

public void init()
{
    parserTimerTask = new TimerTask() {

        @Override
        public void run() {
            XmlParser.parsePage();
        }
    };

    parserTimer = new Timer();
    parserTimer.scheduleAtFixedRate(parserTimerTask, 0, PERIOD);
}

@Override
public void contextDestroyed(ServletContextEvent arg0) {
    Logger logger = Logger.getRootLogger();
    logger.info("DETECT TOMCAT SERVER IS GOING TO SHUT DOWN");
    logger.info("CANCEL TIMER TASK AND TIMER");

    otsParserTimerTask.cancel();

    otsParserTimer.cancel();

    logger.info("CANCELING COMPLETE");
}

@Override
public void contextInitialized(ServletContextEvent arg0) {

}

现在我的新问题:

  • 我首先取消TimerTask然后取消Timer,这是正确的吗?

  • 我还有其他事吗?

谢谢!

UPDATE

它不起作用 . 我在contextDestroyed()方法中放了一些日志语句,在关闭Tomcat之后,日志文件只有以下内容:

PowderGodAppWebService - > [2012年2月7日04:09:46] INFO(PowderGodAppWebService.java:45):: DETECT TOMCAT服务器即将关闭PowderGodAppWebService - > [2012年2月7日04:09:46] INFO(PowderGodAppWebService . java:46)::取消定时器任务和定时器

CANCELING COMPLETE 不存在 .

我还检查了正在运行的进程(我不是Linux专家,所以我只使用Mac的Activity Monitor .

  • 确保没有正在运行的java进程

  • 启动Tomcat,记下该java进程的PID

  • 停止Tomcat

  • 发现Tomcat进程消失了

  • 启动Tomcat,记下该java进程的PID

  • 部署我的war文件

  • 对过程进行采样,参见[Timer-0]线程

  • 关闭Tomcat

  • 发现该过程仍然存在

  • 对流程进行抽样

  • 参见[Timer-0]仍然存在

FIXED

我将我的代码更改为 parserTimer = new Timer(true); ,以便我的计时器作为守护程序线程运行,因为在Tomcat实际关闭后调用 contextDestroyed() .

“在向任何ServletContextListener通知上下文破坏之前,所有servlet和过滤器都将被销毁 . ”

http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContextListener.html

4 回答

  • 1

    not 在Java EE环境中使用 Timer !如果任务抛出运行时异常,那么整个 Timer 将被终止并且将不再运行 . 您基本上需要重新启动整个服务器以使其再次运行 . 此外,它对系统时钟的变化很敏感 .

    请改用ScheduledExecutorService . 它对任务中抛出的异常和系统时钟的变化都不敏感 . 您可以通过 shutdownNow() 方法关闭它 .

    以下是整个 ServletContextListener 实现的示例(注意:由于新的 @WebListener 注释, web.xml 中无需注册):

    @WebListener
    public class BackgroundJobManager implements ServletContextListener {
    
        private ScheduledExecutorService scheduler;
    
        @Override
        public void contextInitialized(ServletContextEvent event) {
            scheduler = Executors.newSingleThreadScheduledExecutor();
            scheduler.scheduleAtFixedRate(new YourParsingJob(), 0, 5, TimeUnit.HOUR);
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent event) {
            scheduler.shutdownNow();
        }
    
    }
    
  • -1

    当servlet即将被卸载时,调用servlets destroy方法 . 您可以从那里取消计时器,前提是您更改了parserTimer本身的范围以使其成为实例变量 . 如果只从init和destroy中访问它,我没有看到它的问题 .

    servlet引擎可以在它认为合适的时候自由卸载servlet,但是在实践中我只看到它被称为servlet引擎被停止 - 其他人可能有其他经验,虽然这可能证明我错了 .

  • 58

    尝试使用框架进行调度 .

    如果您调整Spring Framework,则可以使用内置调度功能 .

    使用Spring进行调度时,我从来没有停止应用服务器的任何问题

  • -2

    parseTimer.purge() 放入onContetexyDestroyed.It将删除队列中的所有计时器(如果存在) .

相关问题