更改操作系统时间时 sleep() 中的 Java 错误 : any workaround?

标签 java sleep clock

让我烦恼的错误与this ticket相同.基本上,如果您将操作系统时钟更改为过去的某个日期,则在更改时 hibernate 的所有线程都不会醒来。

我正在开发的应用程序旨在 24/24 运行,我们希望能够在不停止它的情况下更改操作系统日期(例如,从夏令时切换到冬令时)。目前发生的情况是,当我们将日期更改为过去时,应用程序的某些部分就会卡住。我在 Windows XP 和 Linux 2.6.37 以及最近的 JVM (1.6.0.22) 的多台机器上观察到这一点。

我尝试了许多 Java hibernate 原语,但它们都有相同的行为:

  • Thread.sleep(long)
  • Thread.sleep(long, int)
  • 对象.等待(长)
  • Object.wait(long, int)
  • Thread.join(long)
  • Thread.join(long, int)
  • LockSupport.parkNanos(长)
  • java.util.Timer
  • javax.swing.Timer

现在,我不知道要解决这个问题。我认为我无能为力防止 hibernate 线程卡住。但至少,我想在检测到危险的系统时钟更改时警告用户。

我想出了一个检测此类变化的监控线程:

    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            long ms1 = System.currentTimeMillis();
            long ms2;
            while(true) {
                ms2 = ms1;
                ms1 = System.currentTimeMillis();
                if (ms1 < ms2) {
                    warnUserOfPotentialFreeze();
                }
                Thread.yield();
            }                    
        }
    });
    t.setName("clock monitor");
    t.setPriority(Thread.MIN_PRIORITY);
    t.setDaemon(true);
    t.start();

问题在于,这会使应用程序在空闲时从 2% 的 CPU 使用率增长到 15%。

您是否有解决原始问题的想法,或者您是否可以想出另一种方法来监控线程卡住的出现?

编辑

Ingo 建议不要碰系统时钟。我同意通常不需要它。问题是我们无法控制客户使用他们的计算机做什么(我们计划销售数百份)。

更糟的是:我们的一台机器在没有任何人工干预的情况下出现了这个问题。我猜操作系统 (Windows XP) 会定期将其时钟与 RTC 时钟同步,这会使操作系统时钟自然地回到过去。

结语

我发现我问题中的某些陈述是错误的。我最初的问题实际上有两个不同的原因。现在,我可以肯定地说两件事:

  1. 仅在我的机器上(带有内核 2.6.37 和 OpenJDK 64 位 1.6.0_22 的 archlinux),Thread.sleepObject.waitThread.join, LockSupport.parkNanos 有同样的问题:它们只有在系统时钟到达“目标”唤醒时间时才会唤醒。然而,我的 shell 中的一个简单的 sleep 并没有出现这个问题。

  2. 在我测试的所有机器上(包括我的),java.util.Timerjava.swing.Timer 都有同样的问题(它们被阻塞了直到达到“目标”时间)。

所以,我所做的是用一个更简单的实现替换了所有 java 的 Timer。这解决了除我之外的所有机器的问题(我只希望我的机器是异常(exception)而不是规则)。

最佳答案

根据错误票,您的线程没有被卡住,一旦时钟 catch 修改前的位置,它们就会恢复(因此,如果他们将时钟后移一个小时,您的线程将在 1 小时后恢复) .

当然,那仍然不是很有用。根本原因似乎是 Thread.sleep() 解析为系统调用,该系统调用使线程进入 hibernate 状态,直到将来某个特定的时间戳,而不是特定的持续时间。要解决这个问题,您需要实现您自己的 Thread.sleep() 版本,该版本使用 System.nanoTime() 而不是 System.currentTimeMillis() 或任何其他时间相关的 API。但是,我不能说如何在不使用内置 Thread.sleep() 的情况下做到这一点。

编辑:

或者,如果您使用另一种语言(如 C 或您喜欢的任何其他语言)创建一些外部应用程序,该应用程序除了等待指定的持续时间然后退出外什么都不做。然后,不用在 Java 中调用 Thread.sleep(),您可以生成此外部进程的一个新实例,然后对其调用 waitFor()。这将出于所有实际目的“hibernate ”Java 线程,只要您的外部应用程序能够 hibernate 正确的时间,它就会在正确的时间恢复,而不会被卡住,也不会扰乱 CPU。

似乎要解决这个问题还有很长的路要走,但这是我能想到的唯一可行的解​​决方法。此外,鉴于生成外部进程是一项相对昂贵的操作,如果您 hibernate 时间相对较长(例如数百毫秒或更长时间),它可能效果最佳。对于较短的持续时间,它可能会继续消耗 CPU。

关于更改操作系统时间时 sleep() 中的 Java 错误 : any workaround?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5909574/

相关文章:

java - 从父类(super class)调用子类方法,该方法在另一个子类中不可用

java - Selenium 找不到 <p :calendar> day by using By. linkText()

java - Wait()、Notify()、计时器和 Jbuttons

c++ - 极度 CPU 密集型闹钟

java - 如何将 java.sql.Timestamp 格式化为 (hh :mm AM/PM)

vmware - 如何解决虚拟机的时钟漂移?

java - 如何访问 2D 按钮阵列中的一个按钮? Java Swing

java - 更新 JPA 中的一对一关系

java - 在Java中以一定的时间间隔提供 sleep 间隔

android - 如何在android中将线程从 sleep 中唤醒