6

我在 Apache Tomcat 上使用 JSP/Servlet。我必须每 10 分钟运行一次方法。我怎样才能做到这一点?

4

2 回答 2

10

由于您使用的是 Tomcat,它只是一个准系统 servletcontainer,因此您不能使用@ScheduleJava EE 规范推荐的 EJB。你最好的选择是ScheduledExecutorService来自 Java 1.5 的java.util.concurrent包。您可以通过以下方式触发此操作ServletContextListener

@WebListener
public class BackgroundJobManager implements ServletContextListener {

    private ScheduledExecutorService scheduler;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new SomeTask(), 0, 10, TimeUnit.MINUTES);
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        scheduler.shutdownNow();
    }

}

SomeTask类看起来像这样:

public class SomeTask implements Runnable {

    @Override
    public void run() {
        // Do your job here.
    }

}

如果您实际上使用的是真正的 Java EE 容器,它支持 EJB 并且全部都在 em 上(如 Glassfish、JBoss AS、TomEE 等),那么您可以使用@Singleton带有方法的 EJB @Schedule。这样容器就会担心池化和销毁线程。您只需要以下 EJB:

@Singleton
public class SomeTask {

    @Schedule(hour="*", minute="*/10", second="0", persistent=false)
    public void run() {
        // Do your job here.
    }

} 

请注意,通过这种方式,您可以继续以通常的方式(@PersistenceContext等等)透明地使用容器管理的事务,这是不可能的ScheduledExecutorService——您必须手动获取实体管理器并手动启动/提交/结束事务,但您会默认情况下,像 Tomcat 这样的准系统 servletcontainer 上已经没有其他选项了。

请注意,您永远不应Timer在所谓的“终生”运行的 Java EE Web 应用程序中使用 a。它具有以下主要问题,使其不适合在 Java EE 中使用(引自Java Concurrency in Practice):

  • Timer对系统时钟的变化很敏感,ScheduledExecutorService不是。
  • Timer只有一个执行线程,所以长时间运行的任务会延迟其他任务。ScheduledExecutorService可以配置任意数量的线程。
  • 任何运行时异常都会在杀死该线程时引发TimerTask,从而导致Timer死机,即计划任务将不再运行(直到您重新启动服务器)。ScheduledThreadExecutor不仅可以捕获运行时异常,还可以让您根据需要处理它们。抛出异常的任务将被取消,但其他任务将继续运行。
于 2013-04-03T14:03:26.663 回答
3

阅读ScheduledExecutorService它必须由ServletContextListener启动

public class MyContext implements ServletContextListener 
{
    private ScheduledExecutorService sched;

    @Override
    public void contextInitialized(ServletContextEvent event) 
    {
        sched = Executors.newSingleThreadScheduledExecutor();
        sched.scheduleAtFixedRate(new MyTask(), 0, 10, TimeUnit.MINUTES);
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) 
    {
        sched.shutdownNow();
    }
}

此外,您可以尝试使用ServletContextListener中的 Java Timer,但不建议在 Java EE 容器中使用它,因为它会从容器中夺走对 Thread 资源的控制。(ScheduledExecutorService 的第一个选项是要走的路)。

Timer timer = new Timer("MyTimer");
MyTask t = new MyTask();

//Second Parameter is the specified the Starting Time for your timer in
//MilliSeconds or Date

//Third Parameter is the specified the Period between consecutive
//calling for the method.

timer.schedule(t, 0, 1000*60*10);

MyTaskimplementsTimerTask是一个实现Runnable接口的类,所以你必须用你的代码覆盖run方法:

class MyTask extends TimerTask 
{
  public void run() 
  { 
    // your code here
  }
}
于 2013-04-03T12:44:17.157 回答