На основе таймера
Если вы ищете ванильное решение, которое придерживается "концепции таймера" , вы можете просто вычислить правильный временной интервал и позволить задаче, когда она готово, снова перепланировать себя с правильным вычисленным временем для следующего выполнения.
См. также Метод вызова в дату / время . Будет выглядеть примерно так:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
public static ScheduledFuture<?> scheduleFor(Runnable runnable, ZonedDateTime when) {
Instant now = Instant.now();
// Use a different resolution if desired
long secondsUntil = ChronoUnit.SECONDS.between(now, when.toInstant());
return scheduler.schedule(runnable, secondsUntil, TimeUnit.of(ChronoUnit.SECONDS));
}
public static ZonedDateTime nextDate() {
return ZonedDateTime.now().plusMonths(1);
}
И тогда у вас есть задача примерно как
public class MyTask implements Runnable {
// ...
@Override
public void run() {
// TODO Your stuff ...
// Reschedule
scheduleFor(this, nextDate());
}
}
И сначала запускайте ее как
scheduleFor(task, ZonedDateTime.now().withDayOfMonth(10));
Недостатки
Очевидно, что это решение, поскольку оно основано на таймере , имеет большой недостаток, заключающийся в том, что оно может легко дрейфовать и выходить из синхронизации c. Например, если ваше системное время изменяется или если выполнение задачи занимает так много времени, что вы переноситесь на следующий день. конец.
Если все это не является для вас фактором, он, скорее всего, будет работать так, как задумано.
В противном случае вам, вероятно, следует go для другого, похожего на crontab подхода, где дата периодически проверяется, и как только он соответствует, он выполняет задачу. В отличие от выполнения с фиксированным смещением, как в «выполнить за ... секунд» .