如何运行在固定的时间间隔后台作业的方法? [重复](How to run a backgroun

2019-08-19 06:14发布

这个问题已经在这里有一个答案:

  • 如何运行在基于Servlet的Web应用程序的后台任务? 5个回答

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

Answer 1:

正如你在Tomcat中,这仅仅是一个准系统servletcontainer,您不能使用EJB的@Schedule这是由Java EE规范建议。 最好的办法是那么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.
    }

}

如果您实际上使用与EJB支持和所有他们一个真正的Java EE容器(比如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应用程序。 它有这使得它不适合于Java EE的(转引自使用以下主要问题在实践中的Java并发 ):

  • Timer是系统时钟的变化很敏感, ScheduledExecutorService是没有的。
  • Timer只有一个执行线程,所以长时间运行的任务可以延迟其他任务。 ScheduledExecutorService可以与任何数量的线程来配置。
  • 在抛出的任何运行时异常TimerTask杀死一个线程,从而使Timer (在重新启动服务器)死了,即计划的任务将不再运行。 ScheduledThreadExecutor不仅捕获运行时异常,但它可以让你处理他们,如果你想要的。 任务,抛出的异常将被取消,但其他任务将继续运行。


Answer 2:

阅读关于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();
    }
}

此外,您可以尝试使用Java 定时器从ServletContextListener来 ,但它不是在一个Java EE容器推荐的,因为它需要远离容器线程资源的控制。 (与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);

MyTask实现TimerTask是实现了一类Runnable ,所以你必须重写你的代码的run方法接口:

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


文章来源: How to run a background job method at fixed intervals? [duplicate]