views:

732

answers:

5

I need to run a callable at a specific time of day. One way to do it is to calculate the timediff between now and the desired time , and to use the executor.scheduleAtFixedRate .

Have a better idea?

executor.scheduleAtFixedRate(command, TIMEDIFF(now,run_time), period, TimeUnit.SECONDS))

+10  A: 

For this kind of thing, just go ahead and install Quartz. EJB has some support for this kind of thing but really you just want Quartz for scheduled tasks.

That being said, if you insist on doing it yourself (and I'd recommend not), use the ScheduledThreadPoolExecutor.

ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(4);
ScheduledFuture<?> future =
  executor.scheduleAtFixedRate(runnable, 1, 24, TimeUnit.HOUR);

which will run the Runnable every day with an initial delay of one hour.

Or:

Timer timer = new Timer();
final Callable c = callable;
TimerTask task = new TimerTask() {
  public void run() {
    c.call();
  }
}
t.scheduleAtFixedRate(task, firstExecuteDate, 86400000); // every day

Timer has a somewhat simpler interface and was introduced in 1.3 (the other is 1.5) but a single thread executes all tasks whereas the first one allows you to configure that. Plus ScheduledExecutorService has nicer shutdown (and other) methods.

cletus
+1  A: 

I would recommend using Quartz Framework. This will allow you to schedule jobs in a cron like fashion.

kgiannakakis
A: 

Great , thanks!

yossale
Installing Quartz is really just downloading the jar file. If you are using Spring you just need to add some basic configuration to make it work. I think you will find that its worth it.
Nicolai
http://www.opensymphony.com/quartz/wikidocs/QuickStart.html
Nicolai
BTW it's more common to comment on the question, a particular answer or to edit your question rather than posts an answer as a comment (less clutter).
cletus
+2  A: 

You can user JDK Timer and dont need to calculate the time difference:

Timer timer = new Timer();
Date executionDate = new Date();
long period = 24 * 60 * 60 * 1000;
timer.scheduleAtFixedRate(
    new TimerTask() {
        @Override
        public void run() {
            // the task
        }
    },
    executionDate,
    period);
Guillaume
Yes, thats what he meant in the original post. :)
Adeel Ansari
This would execute for the first time immediately when the code is run. As I read the original post, he doesn't want the first execution to be until the desired time.
Nicolai
I havent tried the code, the the doc specifies that the execution is "beginning at the specified time".
Guillaume
A: 

Quartz is a great idea, but might be a bit of overkill depending on what you need. I think youre real issue is trying to cram your service into a servlet, when you aren't actually listening to incoming HttpServletRequests. Instead, consider using a ServletContextListener to start up your service, and a Timer, as Maurice suggested:

web.xml:

com.myCompany.MyListener And then your class looks like this:

public class MyListener implements ServletContextListener {

/** the interval to wait per service call - 1 minute */
private static final int INTERVAL = 60 * 60 * 1000;

/** the interval to wait before starting up the service - 10 seconds */
private static final int STARTUP_WAIT = 10 * 1000;

private MyService service = new MyService();
private Timer myTimer;

public void contextDestroyed(ServletContextEvent sce) {
    service.shutdown();
    if (myTimer != null)
            myTimer.cancel();
}

public void contextInitialized(ServletContextEvent sce) {
    myTimer = new Timer();
    myTimer.schedule(new TimerTask() {
            public void run() {
                    myService.provideSomething();
            }
    },STARTUP_WAIT, INTERVAL
  );
}

}

ariso