我已将一个WAR文件部署到Tomcat服务器,该类之一将在启动时调用,然后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),它具有以下条目:
严重:Web应用程序[/ MyApplication]似乎已启动名为[Timer-0]的线程,但未能停止它。 这很可能造成内存泄漏。
我了解这是由我安排计时器引起的,但我的问题是:
setDeamon
谢谢!
更新
根据一些搜索和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) { }
现在我的新问题是:
没用 我将一些日志记录语句放入contextDestroyed()方法中,在关闭Tomcat之后,日志文件仅具有以下内容:
PowderGodAppWebService-> [2012年2月7日04:09:46 PM]信息(PowderGodAppWebService.java:45):: DETECT TOMCAT服务器即将关闭PowderGodAppWebService-> [2012年2月7日04:09:46 PM] INFO(PowderGodAppWebService。 java:46)::取消计时器任务和计时器
取消完成 不存在。
我还检查了正在运行的进程(我不是Linux专家,所以我只使用Mac的活动监视器。
固定
我将代码更改为,parserTimer=newTimer(true);以便计时器作为守护程序线程运行,因为contextDestroyed()在Tomcat实际上关闭后调用了gets。
parserTimer=newTimer(true);
contextDestroyed()
“在通知任何ServletContextListener上下文破坏之前,所有Servlet和过滤器都将被破坏。”
http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContextListener.html
千万 不能 使用Timer在Java EE的环境!如果任务抛出运行时异常,则整个Timer事件将被杀死,并且将不再运行。基本上,您需要重新启动整个服务器才能使其再次运行。而且,它对系统时钟的变化很敏感。
Timer
使用ScheduledExecutorService代替。它对任务中引发的异常或系统时钟的更改不敏感。您可以通过其shutdownNow()方法关闭它。
ScheduledExecutorService
shutdownNow()
这是整个ServletContextListener实现的示例(请注意:web.xml由于有了新的@WebListener注释,因此无需注册):
ServletContextListener
web.xml
@WebListener
@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(); } }