完全独立于系统时间变化的Java调度器

完全独立于系统时间变化的Java调度器,java,timer,32bit-64bit,scheduler,ntp,Java,Timer,32bit 64bit,Scheduler,Ntp,使用Java定时器,然后切换到ScheduledExecutorService,但我的问题没有解决。 因为在系统时间更改(通过ntpd)之前计划的任务不会在指定的延迟上执行。没有日志,因为没有发生任何事件:( 在64位linux上的我的目标中使用jre 1.6.02664位 更新:ScheduledExecutorService在Windows上运行正常。问题只出现在运行64位JVM的基于64位Linux的系统上。它运行正常 在…上 运行32位JVM的64位linux…奇怪。在任何博客上也没有找

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

在64位linux上的我的目标中使用jre 1.6.02664位

更新:ScheduledExecutorService在Windows上运行正常。问题只出现在运行64位JVM的基于64位Linux的系统上。它运行正常 在…上 运行32位JVM的64位linux…奇怪。在任何博客上也没有找到相同的参考

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

我已针对JDK提交了缺陷,该缺陷已被接受,但已被关闭并关闭 标记为的副本。如果您觉得合适,请投赞成票 修好它是值得的……我不知道为什么它几年来一直没有修好

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

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);
    }

}

我针对同一个问题进行了研究,但没有找到解决方案。我查看了Quartz和所有内置JRE方法。nanotime方法可能会使用每个CPU的单调时钟,但我相信,如果线程迁移到另一个CPU,则会有大的跳跃风险。我的结论如下:

  • 将NTP配置为永远不会有大的时间跳转。仅缓慢地转换时间。仅在停机期间手动应用大的时间跳转
  • 使用多个较短的超时,并需要两个超时来声明远程计算机已死机。如果您只有一个系统计时本身,这将不会有帮助,但可以帮助处理多个系统
  • 有意使用远程机器定期向您发送唤醒信息。如果您自己的时钟在两次唤醒之间倒转,则您知道所有计时器都将延迟启动
  • 基本上,这是一个巨大的痛苦,但没有灵丹妙药。

    在系统时间倒转期间有一个整体调度,这也会影响非常基本的Object.wait&Thread.sleep方法。当系统时间倒转几秒时,让Java应用程序运行变得太危险。你永远不知道Java应用程序会发生什么到头来

    因此,我们决定:

    • 编写看门狗脚本(非Java:)以检查时间更改
    • 如果时间倒转一定量,请关闭并重新启动Java应用程序
    另一种可能性是转移到32位JVM,但我们使用的是JNI,然后目标平台上使用的本机库不兼容32位。根据我们的经验,32位JVM将我们的目标限制为1.6G堆,这对我们来说根本不够

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

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

    • 将NTP配置为永远不会有大的时间跳跃。只是浪费时间 慢慢地。仅在停机期间手动应用大时间跳转

    此示例代码在我的机器ubuntu 11.10[32位]、JVM 1.6.0_21[32位]上运行良好。更改系统时钟不会影响执行。是的,还检查了它在运行32位jvm的64位linux上运行良好:(.相应地更新了我的问题。我只想指出,在这种情况下,指定纳秒是没有意义的。在内部,代码仍然更改为毫秒。因此
    worker.schedule(这个,100000000,TimeUnit.nanoseconds);
    worker.schedule(这个,1,TimeUnit.SECONDS)相同;
    @ChrisDolan谢谢。但我更关注的是日程安排问题。你能将系统设置为GMT吗?GMT没有夏令时。但你最终应用了这些解决方案吗。对我来说,这些是不可能的:)。@YoK,是的,三个都是。我的场景是检测主服务是否/何时死亡,以便备份可以自动接管。在我使用过的所有NTP配置中,行为都是:如果同步在N分钟内(比如2分钟),则以每分钟X毫秒的速率(比如20分钟)缓慢地将时钟旋转到正确的时间。如果同步时间超过N分钟,则NTP将发出系统日志消息警告错误并变为被动。有趣的。。。将要求我的NTP人员查看它。
    nanoTime
    应在所有CPU中保持一致-请参阅@TomAnderson cool,谢谢更新。我的信息已经过时了。是否有任何计时器实现利用了这一点?接受这个答案作为解决方法:(。在等待适当的解决方案时。我不明白,它对JVM的影响有多大。从您的aswer来看,它似乎是一个关键错误。例如,如果我使用Object.wait(1),时钟向后移动——这是否意味着线程永远不会被唤醒?@BegemoT它并不意味着它永远不会被唤醒……但它会在(时钟向后移动+1)之后被唤醒。这是危险的。而且,它只会发生在64位linux上的64位JVM上。