定时器导致Tomcat服务器出现问题

时间:2013-02-20 16:40:36

标签: java tomcat timer

我想在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.

有什么更好的方法来实现或避免这种情况?

3 个答案:

答案 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应用程序启动和停止时启动和停止计时器。