ScheduledExecutorService
You can use the ScheduledExecutorService
(documentation) class, which is available since Java 5. It will yield a ScheduledFuture
(documentation) which can be used to monitor the execution and also cancel it.
In particular, the method:
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
which
Submits a one-shot task that becomes enabled after the given delay.
But you can also look into the other methods, depending on the actual use case (scheduleAtFixedRate
and versions accepting Callable
instead of Runnable
).
Since Java 8 (Streams, Lambdas, ...) this class becomes even more handy, due to the availability of easy conversion methods between the old TimeUnit
and the newer ChronoUnit
(for your ZonedDateTime
), as well as the ability to provide the Runnable command
as lambda or method reference (because it is a FunctionalInterface
).
Example
Let's have a look at an example doing what you ask for:
// Somewhere before the method, as field for example
// Use other pool sizes if desired
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));
}
A call is simple:
ZonedDateTime when = ...
ScheduledFuture<?> job = scheduleFor(YourClass::yourMethod, when);
You can then use the job
to monitor the execution and also cancel it, if desired. Example:
if (!job.isCancelled()) {
job.cancel(false);
}
Notes
You can exchange the ZonedDateTime
parameter in the method for Temporal
, then it also accepts other date/time formats.
Do not forget to shutdown the ScheduledExecutorService
when you are done. Else you will have a thread running, even if your main program has finished already.
scheduler.shutdown();
Note that we use Instant
instead of ZonedDateTime
, since zone information is irrelevant to us, as long as the time difference is computed correctly. Instant
always represents the time in UTC, without any weird phenomena like DST. (Although it does not really matter for this application, it is just cleaner).