我正在寻找一种在特定日期/时间(特别是ZonedDateTime
)执行给定方法的现代方法。
我知道Timer
类和 Quartz 库,如下所示(线程包括完整的解决方案):
但是这些线程很旧,从那时起就不再使用新的Java功能和库元素。特别地,动手使用任何类型的Future
对象都非常方便,因为它们提供了取消它们的简单机制。
因此,请勿提出涉及Timer
或 Quartz 的解决方案。另外,我想有一个 vanilla 解决方案,而不使用任何外部库。但也可以出于问答考虑而提出建议。
答案 0 :(得分:3)
ScheduledExecutorService
您可以使用ScheduledExecutorService
(documentation)类,该类自Java 5起可用。它将产生一个ScheduledFuture
(documentation),该类可用于监视执行并取消它。
特别是方法:
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
其中
提交一次任务,该任务在给定延迟后启用。
但是您还可以根据实际使用情况(scheduleAtFixedRate
和接受Callable
而不是Runnable
的版本来研究其他方法。
自Java 8(Streams,Lambdas等)以来,由于旧的TimeUnit
与新的ChronoUnit
之间的简便转换方法的可用性(对于您的{ {1}},以及提供ZonedDateTime
作为lambda或方法引用的功能(因为它是Runnable command
)。
让我们看一个示例,该示例完成您所要的工作:
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
始终以UTC表示时间,没有任何 DST 之类的奇怪现象。 (尽管对于此应用程序并不重要,但它更干净)。