补偿计划任务的系统睡眠?

问题描述 投票:0回答:1

我编写了一个简单的概念验证,用于安排可运行程序在给定时间执行。代码完全按照预期工作,并在预定时间执行可运行程序:

public static void main(String[] args) throws InterruptedException, ExecutionException {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss a");
    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    Runnable task = new Runnable() {
        public void run() {
            System.out.println("Task Ran @ " + formatter.format(LocalDateTime.now()));
        }
    };

    LocalDateTime now = LocalDateTime.now();
    LocalDateTime runTime = ciel(ChronoUnit.MINUTES, now.plusMinutes(1));

    Duration duration = Duration.between(now, runTime);
    long initialDelay = duration.toMillis();

    System.out.println("Schedule @ " + formatter.format(now));
    System.out.println("Expected @ " + formatter.format(runTime));
    scheduler.schedule(task, initialDelay, TimeUnit.MILLISECONDS);

    scheduler.shutdown();
    scheduler.awaitTermination(2, TimeUnit.MINUTES);
}

private static LocalDateTime ciel(TemporalUnit precision, LocalDateTime time) {
    return time.truncatedTo(precision).plus(1, precision);
}

输出:

Schedule @ 12/18/2023 11:31:47 AM
Expected @ 12/18/2023 11:33:00 AM
Task Ran @ 12/18/2023 11:33:00 AM

但是,如果我在程序运行时将系统置于睡眠状态并稍后唤醒它,则可运行程序将在计划时间之外执行:

Schedule @ 12/18/2023 11:35:53 AM
Expected @ 12/18/2023 11:37:00 AM
Task Ran @ 12/18/2023 11:39:13 AM

假设操作系统在预定时间之前唤醒,我该如何补偿这一点,以便可运行程序仍然按预期执行?

java scheduled-tasks scheduler scheduling
1个回答
0
投票

正如我在评论中指出的,您观察到的系统挂起/睡眠延迟执行通过

ScheduledExecutorService
安排的任务的问题似乎是已知问题 JDK-8146527,最初于 2016 年初提交。似乎是
ScheduledExecutorService
或其标准实现
ScheduledThreadPoolExecutor
中可用的任何解决方法。

但是,您也许可以通过不同的调度机制来解决这个问题,例如

java.util.Timer
。此外,该特定类提供了一种内置方法,用于“在特定时间点调度执行”,因此,如果您还没有延迟,则无需自己计算延迟。如果您选择使用 Timer 那么您应该确保阅读并理解其文档中表达的警告。看起来可能是这样的:
import java.util.Timer;  // Do not confuse this with javax.swing.Timer
// ...

public static void main(String[] args) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss a");
    Timer timer = new Timer();
    TimerTask task = new TimerTask() {
        public void run() {
            System.out.println("Task Ran @ " + formatter.format(ZonedDateTime.now()));
            timer.cancel();
        }
    };
    ZonedDateTime now = ZonedDateTime.now();
    ZonedDateTime runTime = now.plusMinutes(1);

    System.out.println("Schedule @ " + formatter.format(now));
    System.out.println("Expected @ " + formatter.format(runTime));
    timer.schedule(task, Date.from(runTime.toInstant()));
}

该方法适用于在指定时间安排任务,但我没有好的方法在系统挂起的特定情况下测试它。如果它不能解决该问题,那么您可能需要找到可以处理它的第三方调度程序,或者编写您自己的调度程序。

© www.soinside.com 2019 - 2024. All rights reserved.