惹恼我的错误与此票相同.基本上,如果您将OS时钟更改为过去的日期,则更改时正在休眠的所有线程都不会被唤醒.
我正在开发的应用程序意味着24/24运行,我们希望能够在不停止的情况下更改操作系统日期(例如,从夏季时间切换到冬季时间).目前发生的事情是,当我们将日期更改为过去时,应用程序的某些部分就会冻结.我观察到在多台机器上,在Windows XP和Linux 2.6.37上,以及最近的JVM(1.6.0.22).
我尝试了很多Java睡眠原语,但它们都有相同的行为:
现在,我不想解决这个问题.我认为我无法阻止睡眠线冻结.但我想至少在检测到危险的系统时钟变化时警告用户.
我想出了一个监控线程来检测这些变化:
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();
Run Code Online (Sandbox Code Playgroud)
问题是这使得应用程序在空闲时从2%的CPU使用率增长到15%.
你有想法解决原始问题,或者你能想到另一种监控线程冻结外观的方法吗?
Ingo建议不要触摸系统时钟.我同意通常不需要它.问题是我们无法控制客户对计算机的操作(我们计划销售数百份).
更糟糕的是:我们的一台机器没有任何人工干预就会出现这个问题.我想OS(Windows XP)会定期将其时钟与RTC时钟同步,这使得OS时钟自然会及时回溯.
我发现我的问题中的一些陈述是错误的.我最初的问题实际上涉及两个不同的原因.现在,我可以肯定地说两件事:
在我的机器只(ArchLinux的内核2.6.37与OpenJDK的64位1.6.0_22) ,Thread.sleep,,Object.wait 有同样的问题:他们醒来,只有当系统时钟到达觉醒的"目标"的时间.但是,我的shell中的一个简单不会出现问题.Thread.joinLockSupport.parkNanossleep
在我测试的所有机器上(包括我的),java.util.Timer并且java.swing.Timer具有相同的问题(它们被阻塞直到达到"目标"时间).
所以,我所做的是Timer通过更简单的实现替换了所有的java .这解决了除了我的所有机器的问题(我只希望我的机器不仅仅是一个规则).
根据错误故障单,你的线程没有被冻结,一旦时钟赶上它修改之前的位置就会恢复(所以如果他们将它移回一小时,你的线程将在1小时内恢复).
当然,这仍然不是很有用.根本原因似乎是Thread.sleep()解析为系统调用,该线程将线程置于将来的某个特定时间戳之前,而不是指定的持续时间.要解决此问题,您需要实现自己的版本Thread.sleep(),System.nanoTime()而不是使用System.currentTimeMillis()任何其他时间相关的API.但是,如何在不使用内置的情况下做到这一点Thread.sleep()我不能说.
编辑:
或者,如果您使用另一种语言(如C或您喜欢的任何其他语言)创建一些外部应用程序,除了等待指定的持续时间然后退出,该怎么办.然后,不是在Java中调用Thread.sleep(),而是可以生成此外部进程的新实例,然后在其上调用waitFor().这将"睡眠"Java线程用于所有实际目的,并且只要您的外部应用程序能够在正确的持续时间内休眠,它将在正确的时间恢复而不会被冻结并且不会使CPU崩溃.
似乎还有很长的路可以解决问题,但这是我能想到的唯一可行的解决方法.此外,鉴于产生外部过程是一个相对昂贵的操作,如果你睡了相当长的时间(如几百毫秒或更长),它可能是最好的.对于较短的持续时间,它可能只是继续颠簸CPU.
| 归档时间: |
|
| 查看次数: |
6280 次 |
| 最近记录: |