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

使用Java Timer,然后切换到ScheduledExecutorService,但我的问题没有修复。 在系统时间更改之前安排的任务(通过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); } } 

在Sytem时间向后更改期间,JVM中存在用于整体调度的错误 ,这也会影响非常基本的Object.wait和Thread.sleep方法。 当系统时间切换回甚至几秒钟时,保持Java App运行变得太冒险。 你永远不知道你的Java应用程序最终会是什么。

所以我们决定:

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

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

我知道我们不是最优雅的解决方案,但直到JVM被修复或找到了更好的解决方案,似乎没有任何其他方式。

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

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

我解决了同样的问题并且没有找到解决方案。 我查看了Quartz和所有内置的JRE方法。 纳米方法可能使用每CPU单调时钟,但如果线程迁移到另一个CPU,你冒着大跳跃的风险,我相信。 我的结论如下:

  1. 配置NTP永远不会有大的时间跳跃。 只是慢慢地浪费时间。 仅在停机期间手动应用大时间跳转。
  2. 使用多个较短的超时,并需要两次超时来声明远程计算机已停止。 如果您自己只有一个系统计时,这将无济于事,但可以帮助多个系统
  3. 故意使用远程机器向您发送定期唤醒。 如果你自己的时钟在唤醒之间倒退,那么你知道你的所有计时器都会迟到。

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