更改操作系统时间时 sleep() 中的 Java 错误:任何解决方法?
惹恼我的错误与此票证相同。基本上,如果将操作系统时钟更改为过去的日期,则在更改时处于睡眠状态的所有线程都不会唤醒。
我正在开发的应用程序旨在全天候运行,我们希望能够在不停止的情况下更改操作系统日期(例如,从夏时切换到冬令时)。目前发生的事情是,当我们将日期更改为过去时,应用程序的某些部分就会冻结。我在多台机器上,Windows XP和Linux 2.6.37以及最近的JVM(1.6.0.22)上观察到了这一点。
我尝试了许多Java睡眠原语,但它们都有相同的行为:
- 线程.睡眠(长)
- Thread.sleep(long, int)
- Object.wait(long)
- Object.wait(long, int)
- 线程.连接(长)
- Thread.join(long, int)
- LockSupport.parkNanos(long)
- java.util.Timer
- javax.swing.Timer
现在,我的想法是想解决这个问题。我认为我无能为力,以防止沉睡的线程冻结。但是,我想至少在检测到危险的系统时钟变化时警告用户。
我想出了一个监控线程来检测这些变化:
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时钟同步,这使得操作系统时钟自然地回到过去。
结语
我发现我的问题中的一些陈述是错误的。实际上,我最初的问题涉及两个不同的原因。现在,我可以肯定地说两件事:
仅在我的机器上(内核为2.6.37的archlinux,OpenJDK 64位为1.6.0_22),,,,具有相同的问题:只有当系统时钟达到唤醒的“目标”时间时,它们才会唤醒。但是,我的shell中的一个简单的问题并没有表现出问题。
Thread.sleep
Object.wait
Thread.join
LockSupport.parkNanos
sleep
在我测试的所有机器上(包括我的机器),并且有同样的问题(它们被阻止,直到达到“目标”时间)。
java.util.Timer
java.swing.Timer
所以,我所做的是,我用一个更简单的实现取代了所有的java。这解决了除我的机器以外的所有机器的问题(我只是希望我的机器是一个例外而不是一个规则)。Timer