如何测量Java中不受系统时钟变化影响的时间?

我想测量Java中的经过时间。 但是, System.currentTimeMillis()和(我相信) System.nanoTime()差异可以通过外部更改来更改,例如某人(或系统)更改系统时钟。

使用网络呼叫不是一种选择,因为它可能非常频繁且需要快速返回。

对此有一个共同的解决方案吗?

编辑

对不起,我应该详细说明原因。 它不是为了阻止恶意用户 – 它是客户端发起的空闲注销和日常客户端事件。

这并没有真正回答你的问题,但是错误#6458294意味着在可能的情况下,Sun的nanoTime()实现将使用真正单调的机制(Linux上的CLOCK_MONOTONIC,Windows上的QueryPerformanceFrequency / QueryPerformanceCounter)。 只有当这些不可用时,它才会回归到易受系统时钟变化影响的机制。

如果您对正在运行的硬件有控制(或至少知识),并且可以确保这些时钟机制可用,那么您可能很幸运,nanoTime()也可以。

您可能还想阅读此博文 ,其中更详细地讨论了HotSpot-on-Windows案例。

我认为没有办法做到这一点。

当然没有办法做到这一点,不能被颠覆。 从根本上说,您将受操作系统和JVM的支配,因为当前时间报告给Java应用程序的内容。 可以修补其中任何一个或两个,以便Java代码最终获得伪造的时间戳值。 您可以尝试防范此问题,但黑客需要做的就是修补您的应用以完全禁用许可证检查。

无论您是否使用Java,此“漏洞”都适用于此记录。

如果您试图通过设置时钟来阻止人们破坏许可证方案,您需要存储到目前为止在某种加密和安全存储中看到的最高时间,然后在任何时候禁用该程序不到你所看到的最高值(当然有一些NTP时钟调整和DST更改的余量),或者如果它们以某种方式篡改或删除安全存储。

我不知道如果系统时钟发生变化,nanoTime()是否可能会发生变化,但我认为这是可能的。 nanoTime()也可能不准确。

如果你真的需要防止时钟变化,你可以监视线程中的时钟。 睡眠100毫秒或1000毫秒,然后调用currentTimeMillis()。 如果时钟提前超过1000 + x或已经倒退,则可能时钟发生了变化(或者线程挂起了某些东西,这是可能的)。

如果发生分离,您实际上可以进行网络呼叫检查。 当然,由于插入闰秒 ,网络时间可能会发生变化。 我曾经读过一些科学家的Slashdot评论,他们正在协调来自许多不同来源的天文数据。 在他的实验中添加了闰秒,它基本上毁了它,因为有些网站插入了它而其他网站没有。

另一种可能性是使用低级本机API来获取其他系统计时器。 如系统或网络正常运行时间来校准API。 Windows具有getTickCount()函数,该函数返回自引导以来的毫秒数。 在unix系统上,您可以使用uptime命令进行粗略估计。 您可以定期检查这些值以查看系统时钟是否已更改。

如果您不介意在Java应用程序中添加一些本机代码,请使用:

  • Windows上的QueryPerformanceCounter()QueryPerformanceFrequency() ; 要么

  • 带有CLOCK_MONOTONIC时钟ID的POSIX clock_gettime()函数。

请注意,不建议在多处理器系统上使用x86 TSC寄存器 ,因此最好使用上述API。