我正在寻找一种在给定日期/时间执行给定方法的现代方法(特别是ZonedDateTime
)。
我知道Timer
类和Quartz库,如下所示(线程包括完整的解决方案):
但是那些线程相当陈旧,从那以后就不再使用新的Java特性和库元素了。特别是,接触任何类型的Future
对象都非常方便,因为它们提供了一种取消它们的简单机制。
所以请不要建议涉及Timer
或Quartz的解决方案。此外,我想要一个vanilla解决方案,而不是使用任何外部库。但是,为了问答,请随意提出这些建议。
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这样的奇怪现象。 (虽然这个应用程序并不重要,但它更简洁)。