如何以固定的时间间隔运行后台作业方法?

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

正如您在Tomcat上,它只是一个准系统servlet容器,您不能使用EJB的@Schedule ,这是Java EE规范推荐的。 您最好的选择是Java 1.5的java.util.concurrent包中的ScheduledExecutorService 。 您可以在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. } } 

如果您实际上正在使用具有EJB支持的真实Java EE容器以及所有的em(如Glassfish,JBoss AS,TomEE等),那么您可以使用带有@Schedule方法的@Singleton EJB。 这样容器就会担心汇集和销毁线程。 您只需要以下EJB:

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

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

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

  • Timer对系统时钟的变化很敏感,而ScheduledExecutorService则不然。
  • Timer只有一个执行线程,因此长时间运行的任务可以延迟其他任务。 ScheduledExecutorService可以配置任意数量的线程。
  • TimerTask抛出的任何运行时exception会杀死一个线程,从而导致Timer死机,即计划任务将不再运行(直到重新启动服务器)。 ScheduledThreadExecutor不仅捕获运行时exception,还允许您根据需要处理它们。 抛出exception的任务将被取消,但其他任务将继续运行。

读取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); 

实现TimerTask MyTask是一个实现Runnable接口的类,因此您必须使用您的代码覆盖run方法:

 class MyTask extends TimerTask { public void run() { // your code here } }