我想在Tomcat上运行的servlet上每22分钟运行一个方法。所以我正在使用这段代码:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
update();
} catch (SQLException | NamingException | InterruptedException e1) {
e1.printStackTrace();
}
}
}, 22 * 60 * 1000, 22 * 60 * 1000);
我有一种感觉,这是一种可怕的方式,因为我总是在定时器上遇到错误,每当我上传新版本的servlet时,我都不认为它会停止前一个计时器。然后我得到数据库连接警告。如果我重置一切并重新开始它的罚款。
javax.naming.NameNotFoundException: Name comp is not bound in this Context
at org.apache.naming.NamingContext.lookup(NamingContext.java:770)
at org.apache.naming.NamingContext.lookup(NamingContext.java:153)
at org.apache.naming.SelectorContext.lookup(SelectorContext.java:152)
at javax.naming.InitialContext.lookup(InitialContext.java:411)
at my.app.database.DatabaseManager.connect(DatabaseManager.java:44)
at my.app.database.DatabaseManager.returnInfo(DatabaseManager.java:133)
at my.app.genParse.Generate.updateHistory(Generate.java:89)
at my.app.MyServer$1.run(MyServer.java:52)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
并且还在重新启动时使用新版本:
SEVERE: The web application [/myApp] appears to have started a thread named [Timer-7] but has failed to stop it. This is very likely to create a memory leak.
有什么更好的方法来实现或避免这种情况?
答案 0 :(得分:1)
已经讨论了使用计时器任务的替代方法here。使用ScheduledThreadpoolExecutor
类 MAY 可以帮助解决在上传新版本时仍然运行多个线程的问题,但我不能肯定它会这样做。由于javadoc中讨论的各种原因,此类也优先于Timer
类。
答案 1 :(得分:1)
你不应该在容器中使用Timer
- Timer
生成/重用在容器外部管理的线程,这可能会导致问题。
另请注意,Timer
使用单个线程,如果其中一个实例花费的时间太长,则其他线程的准确度会受到影响。
最后,如果Timer
抛出未经检查的异常,Timer
线程将被终止。
由于这些(和其他)原因,它已基本上不再受欢迎 - ScheduledThreadPoolExecutor是一个更好的选择。
同样,容器内的用户管理线程可能很棘手。 JSR-236(Java EE平台的并发实用程序)将在未来提供一种机制来实现,但现在最好避免使用它。
您可以尝试通过cron安排可重复的任务,也许可以定期调用专用的servlet(或类似的)
答案 2 :(得分:0)
使用ServletContextListener在Web应用程序启动和停止时启动和停止计时器。