Schedule periodic tasks

Tasks can be scheduled for execution in the future. Such tasks can be performed either periodically, or just once. As well, the first execution can be delayed to a specific time in the future.

There are two different styles of implementing a scheduled task:

The first pair is the more modern API. As usual, the more modern API is usually the preferred one. The main difference between these two APIs is that the first always uses relative times, while the second does not. If needed, you always can transform a LocalDateTime, Date, or similar object into a relative time:

LocalDateTime now = LocalDateTime.now();
LocalDateTime futureTime = LocalDateTime.parse("2100-01-01T00:00:00"); 
Long msecsUntil = ChronoUnit.MILLIS.between(now, futureTime);

//with JDK <8
Date futureDate = ...
Long startTime = futureDate.getTime() - System.currentTimeMillis();
(This will only work if the system clock is not reset.)

Example 1

Here's an example of an AlarmClock class, which uses a ScheduledExecutorService:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 Run a simple task once every second, starting 3 seconds from now.
 Cancel the task after 20 seconds.
*/
public final class AlarmClock {
  
  /** Run the example. */
  public static void main(String... args) throws InterruptedException {
    log("Main started.");
    AlarmClock alarmClock = new AlarmClock(3, 1, 20);
    alarmClock.activateAlarmThenStop();
    /*
    To start the alarm at a specific date in the future, the initial delay
    needs to be calculated relative to the current time, as in : 
    Date futureDate = ...
    long startTime = futureDate.getTime() - System.currentTimeMillis();
    AlarmClock alarm = new AlarmClock(startTime, 1, 20);
    This works only if the system clock isn't reset.
    */
    log("Main ended.");
  }
  
  AlarmClock(long initialDelay, long delayBetweenBeeps, long stopAfter){
    this.initialDelay = initialDelay;
    this.delayBetweenRuns = delayBetweenBeeps;
    this.shutdownAfter = stopAfter;
    this.scheduler = Executors.newScheduledThreadPool(NUM_THREADS);    
  }
  
  /** Sound the alarm for a few seconds, then stop. */
  void activateAlarmThenStop(){
    Runnable soundAlarmTask = new SoundAlarmTask();
    ScheduledFuture<?> soundAlarmFuture = scheduler.scheduleWithFixedDelay(
      soundAlarmTask, initialDelay, delayBetweenRuns, TimeUnit.SECONDS
    );
    Runnable stopAlarm = new StopAlarmTask(soundAlarmFuture);
    scheduler.schedule(stopAlarm, shutdownAfter, TimeUnit.SECONDS);
  }

  // PRIVATE 
  private final ScheduledExecutorService scheduler;
  private final long initialDelay;
  private final long delayBetweenRuns;
  private final long shutdownAfter;
  
  private static void log(String msg){
    System.out.println(msg);
  }

  /** If invocations might overlap, you can specify more than a single thread.*/ 
  private static final int NUM_THREADS = 1;
  private static final boolean DONT_INTERRUPT_IF_RUNNING = false;
  
  private static final class SoundAlarmTask implements Runnable {
    @Override public void run() {
      ++count;
      log("beep " + count);
    }
    private int count;
  }
  
  private final class StopAlarmTask implements Runnable {
    StopAlarmTask(ScheduledFuture<?> schedFuture){
      this.schedFuture = schedFuture;
    }
    @Override public void run() {
      log("Stopping alarm.");
      schedFuture.cancel(DONT_INTERRUPT_IF_RUNNING);
      /* 
       Note that this Task also performs cleanup, by asking the 
       scheduler to shutdown gracefully. 
      */
      scheduler.shutdown();
    }
    private ScheduledFuture<?> schedFuture;
  }
} 

Example 2

This example uses the older classes, Timer and TimerTask.

Here, a task is performed once a day at 4 a.m., starting tomorrow morning.

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

public final class FetchMail extends TimerTask {

  /** Construct and use a TimerTask and Timer. */
  public static void main (String... arguments ) {
    TimerTask fetchMail = new FetchMail();
    //perform the task once a day at 4 a.m., starting tomorrow morning
    //(other styles are possible as well)
    Timer timer = new Timer();
    timer.scheduleAtFixedRate(fetchMail, getTomorrowMorning4am(), fONCE_PER_DAY);
  }

  /**
  * Implements TimerTask's abstract run method.
  */
  @Override public void run(){
    //toy implementation
    System.out.println("Fetching mail...");
  }

  // PRIVATE

  //expressed in milliseconds
  private final static long fONCE_PER_DAY = 1000*60*60*24;

  private final static int fONE_DAY = 1;
  private final static int fFOUR_AM = 4;
  private final static int fZERO_MINUTES = 0;

  private static Date getTomorrowMorning4am(){
    Calendar tomorrow = new GregorianCalendar();
    tomorrow.add(Calendar.DATE, fONE_DAY);
    Calendar result = new GregorianCalendar(
      tomorrow.get(Calendar.YEAR),
      tomorrow.get(Calendar.MONTH),
      tomorrow.get(Calendar.DATE),
      fFOUR_AM,
      fZERO_MINUTES
    );
    return result.getTime();
  }
}
 

See Also :
Timers