简体   繁体   中英

how to calculate initialDelay for ScheduledExecutorService#scheduleAtFixedRate

I want to run a task at a specific time say at 7.11pm everyday. I have tried the following piece of code but it is not working.

import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Task3 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            public void run() {
                System.out.println(new Date());
                System.out.println("Hello !!");
            }
        };

        Calendar calendar = Calendar.getInstance();
        long now = calendar.getTimeInMillis();
        calendar.set(Calendar.HOUR, 18);
        calendar.set(Calendar.MINUTE, 11);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        service.scheduleAtFixedRate(runnable, calendar.getTimeInMillis(), 5, TimeUnit.SECONDS);
    }
}

In the above code, I have tried to run the schedule task starting from 7:11pm everyday with an interval of 5 seconds . But it is not behaving as I expected to be. And also If I want to do the same with another condition that the task should be executed only on specific days let's say every Tuesday and Wednesday.

Am I making some kind of mistake in calculating the initialDelay parameter of the method or something else?

Side comment: it would probably be simpler to use an ad hoc library (such as quartz).

The initialDelay parameter gives the number of time unit to wait before running the task. In your case, you need to calculate the time left to 7:11.

So it could look like:

long nextRun = calendar.getTimeInMillis();
long initialDelayMillis = nextRun - now;
long oneDayMillis = 1000L * 60 * 60 * 24;
service.scheduleAtFixedRate(runnable, initialDelayMillis, oneDayMillis, TimeUnit.MILLISECONDS);

but this will only handle basic situations. In particular it won't handle clock adjustments or DST at all. And it won't be easy to say "only on Tuesdays and Wendesdays".

An alternative would be to only schedule the next run and reschedule it at the end of the runnable. That way you can have a finer control on the execution. But bottom line is: see my initial comment.

Preferable would be the scheduledExecutorService. But maybe timer could be used too. For swing the other timer.

Here an example (the timer and timerTask could be stoped with cancel/purge).

 import java.util.Calendar;
 import java.util.Date;
 import java.util.Timer;
 import java.util.TimerTask;

 public class TimeScheduleTest {
  Timer timer = new Timer();
  public static void main(String[] args) {
   new TimeScheduleTest().startApp();
  }

 private void startApp() {
  Calendar calendar = Calendar.getInstance();
  calendar.set(Calendar.DAY_OF_WEEK,Calendar.TUESDAY);
  calendar.set(Calendar.HOUR_OF_DAY, 7);
  calendar.set(Calendar.MINUTE, 11);
  calendar.set(Calendar.SECOND, 0);
  calendar.set(Calendar.MILLISECOND, 0);
  timer.scheduleAtFixedRate(new StartTimer(), calendar.getTime(), 5000);
 } 

 class StartTimer extends TimerTask {
  public void run() {
   System.out.println(new Date());
   System.out.println("Hello !!");
  }
 }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM