ScheduledExecutorService
您可以使用自 Java 5 起可用的 ScheduledExecutorService (documentation) 类。它将产生一个 ScheduledFuture (documentation) 可用于监视执行并取消它。
特别是方法:
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
哪个
提交在给定延迟后启用的一次性任务。
但您也可以查看其他方法,具体取决于实际用例(scheduleAtFixedRate 和接受Callable 而不是Runnable 的版本)。
自从 Java 8(Streams、Lambdas...)以来,由于旧的TimeUnit 和新的ChronoUnit(用于您的ZonedDateTime)之间的简单转换方法的可用性,这个类变得更加方便,以及提供 Runnable command 作为 lambda 或方法引用的能力(因为它是 FunctionalInterface)。
示例
让我们看一个执行您要求的示例:
// 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));
}
调用很简单:
ZonedDateTime when = ...
ScheduledFuture<?> job = scheduleFor(YourClass::yourMethod, when);
然后,您可以使用job 来监控执行并在需要时取消它。示例:
if (!job.isCancelled()) {
job.cancel(false);
}
注意事项
你可以将方法中的ZonedDateTime参数换成Temporal,那么它也可以接受其他日期/时间格式。
完成后不要忘记关闭ScheduledExecutorService。否则即使你的主程序已经完成,你也会有一个线程在运行。
scheduler.shutdown();
请注意,我们使用Instant 而不是ZonedDateTime,因为区域信息与我们无关,只要正确计算时间差即可。 Instant 始终表示 UTC 时间,没有任何 奇怪 现象,如 DST。 (虽然这对这个应用程序来说并不重要,但它更干净)。