答案 0 :(得分:1)
计算机没有那么准确。
因此,您想要什么并不明确(或者,如果您愿意,也不可能)。
'wait 50msec' 不太可能,但接近于它。但是,“运行 200 毫秒”,这很奇怪,而且不太可能。您可能是说:“我有一些任务,大约需要 200 毫秒”?或者你的意思是:我有一个非常快的任务。我想连续做 200 毫秒没有中断,然后停止做一段时间?这也是不可能的,但接近它的事情是可能的。或者你的意思是:我有一个需要很多秒的长时间运行的工作。我希望作业运行 200 毫秒,然后在其轨道上冻结,然后在 50 毫秒后解冻并让它继续运行,等等?这很奇怪,而且不太可能。
在 Java 或现代操作系统上的任何其他语言中“等待 50 毫秒”是一个提示。这将等待大约 50 毫秒。不完全是 50 毫秒。您需要处理“漂移”这一事实。如果您让计算机等待 50 毫秒几百万次,那么您将远不及您预期的时间。有几次可能是 51 毫秒,有时可能是 52 毫秒。
以下是您可以做的事情:
int time = 0;
while (true) {
String formattedTime = formatTime(time);
renderToWidget(formattedTime);
time++;
Thread.sleep(1000L); // wait one second
}
以上内容完全错误。随着秒表的运行,它会越来越远。相反,您应该这样做:
private static final long NANOS_IN_SECOND = 1000000000;
...
long start = System.nanoTime();
while (true) {
long secondsPassed = (System.nanoTime() - start) / NANOS_IN_SECOND;
String formattedTime = formatTime(secondsPassed);
renderToWidget(formattedTime);
Thread.sleep(500L); // why not update a little more often?
}
另一个重要的想法是,不是“等待 50 毫秒”,而是“计算下一个唤醒时间,然后无论等待多久,直到那一刻到来”的想法更好地解决了许多问题。例如,如果您想为游戏编写一个“帧率限制器”,以便游戏不会以高于 60fps 的速度渲染帧,您可以这样做:
private static final long NANOS_PER_FRAME = 1000000000 / 60; // 60 fps
...
long now = System.nanoTime();
long done = now + NANOS_PER_FRAME;
Frame frame = renderFrame();
screen.show(frame);
long toWait = System.nanoTime() - done;
if (toWait > 0) waitNanos(toWait);
换句话说,该模型不是“等待一定时间”,而是说每 x 毫秒发生一个事件,这本质上意味着该事件有 1/x 的最大运行时间,然后您编写循环无论等待多久,如果事件运行得比这更快,它都需要等待“填满剩余部分”。
哪一个适合你?不知道 - 你的问题没有具体说明。
Java 没有“只是冻结线程”功能。相反,线程本身中的代码需要不时签入,然后您可以在那里冻结。例如,如果您有一个比特币矿工需要每大约 200 毫秒停止一次,那么只要需要显式等待的代码非常频繁地“签入”(在计时框架的控制下调用某些方法),就可以工作。该代码可以使用上述技术来检查是否应该进行冻结,如果应该进行,只需使用 Thread.sleep(time)
来等待您的计算状态您应该等待的时间。如果在线程中运行的代码不是您编写的,也不能由您更改,则 Java 线程不是该工作的工具。
注意:请注意 System.currentTimeMillis()
是一个棘手的问题。如果用户弄乱系统时钟,该值可能会漂移甚至倒退。如今,大多数计算机都运行时间守护程序,使时钟与某个时间服务器保持同步,但这也意味着可能会发生漂移。因此,使用 System.cTM 来衡量经过的时间是一个坏主意。