Java调度程序,完全独立于系统时间变化

2022-09-02 22:28:29

使用Java Timer,然后切换到SchpendentExecutorService,但我的问题没有得到解决。由于在系统时间更改(通过 ntpd)之前计划的任务不会在指定的延迟时执行。没有日志,因为:(没有任何事情发生。

在64位Linux上使用jre 1.6.0_26 64位。

更新:ScheduledExecutorService在Windows上运行良好。问题仅在运行64位JVM的基于64位Linux的系统上。它在运行32位JVM的64位Linux上运行良好...奇怪。也没有在任何博客上找到任何相同的参考。

IBM的JAVA SDK也有同样的问题(ibm-java-sdk-7.0-0.0-x86_64-archive.bin)。

我曾向JDK提交过缺陷7139684,它被接受但已被关闭并标记为6900441的副本。请投票支持它,如果你觉得它值得修复它...我不知道为什么它没有被修复超过几年

以下是我用于测试此问题的示例代码:

package test;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author yogesh
 *
 */
public class TimerCheck  implements Runnable {

    ScheduledExecutorService worker;


    public TimerCheck(ScheduledExecutorService worker) {
        super();
        this.worker = worker;
        this.worker.schedule(this, 1, TimeUnit.SECONDS);
    }

    private static void update() {
        System.out.println("TimerCheck.update() "+new Date(System.currentTimeMillis()));
    }

    @Override
    public void run() {
            update();
            worker.schedule(this, 1, TimeUnit.SECONDS);
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        ScheduledExecutorService worker = Executors.newScheduledThreadPool(1);
        new TimerCheck(worker);
    }

}

答案 1

JVM中存在一个错误,用于在系统时间向后变化期间的整体调度,这也影响了非常基本的Object.wait和Thread.sleep方法。当系统时间切换回来甚至一定秒数时,保持Java应用程序运行的风险太大。你永远不知道你的Java应用程序最终会变成什么样子。

因此,我们决定:

  • 编写看门狗脚本(非Java:))来检查时间变化。
  • 如果时间切换回一定数量,请关闭并重新启动Java应用程序。

另一种可能性是迁移到32位JVM,但是我们使用的是JNI,然后在目标平台上使用的本机库与32位不兼容。此外,根据我们的经验,32位JVM将我们的目标限制为1.6G堆,这对我们来说根本不足够。

我知道我们的解决方案不是最优雅的解决方案,但是在JVM修复或找到更好的解决方案之前,似乎没有其他方法。

编辑:除了上述解决方案之外,我们还在考虑Chris的第一个建议:

  • 将 NTP 配置为永远不会有大的时间跳跃。只是慢慢地把时间压得水泄不通。仅在停机期间手动应用大时间跳跃。

答案 2

我遇到了同样的问题,但还没有找到解决方案。我研究了Quartz和所有内置的JRE方法。纳米时间方法可能使用每CPU单调时钟,但是如果线程迁移到另一个CPU,您将面临大跳跃的风险,我相信。我的结论如下:

  1. 将 NTP 配置为永远不会有大的时间跳跃。只是慢慢地把时间压得水泄不通。仅在停机期间手动应用大时间跳跃。
  2. 使用多个较短的超时,并需要两个超时来声明远程计算机死亡。如果您只有一个系统计时本身,这将无济于事,但可以帮助多个系统
  3. 故意使用远程计算机定期向您发送唤醒。如果您自己的时钟在唤醒之间倒退,那么您就知道所有计时器都会延迟点火。

基本上,这是一个巨大的痛苦,但没有银弹。