用Java创建一个简单的计时器

我似乎无法弄清楚如何在java中创建一个简单的计时器。 我需要做的只是显示时间,真的。 所以只是一个开始的方法,它一直在计数,如0:00,0:01,0:02等。我已经看到了一些其他类似的论坛post,但所有的代码是有点复杂的我的水平理解; 我是java的新手。 但是,制作一个只执行这种基本function的计时器并不难吗? 如果有人可以提供帮助,将非常感谢:)

这并不困难。 但是,我会提醒你,我已经看到了一些关于堆栈溢出的非常混乱的答案,在某些情况下编码习惯令人震惊,所以要非常小心。 首先让我回答这个问题。

如果看起来是程序员在实现计时器时犯的最大错误,那就是认为他们需要一些东西来跟踪当前时间。 也就是说,他们编写某种循环,每秒递增一个变量或者某些如此愚蠢的东西。 您无需编写代码来跟踪时间。 System.currentTimeMillis()函数将为您执行此操作,并且它可以非常准确地完成。

定时器代码将涉及许多程序员混淆的两个方面:

  1. 计算时间
  2. 刷新显示

计算显示时间所需要做的就是记录计时器启动的时间:

 long startTime = System.currentTimeMillis(); 

稍后,当您想要显示时间量时,您只需从当前时间中减去它。

 long elapsedTime = System.currentTimeMillis() - startTime; long elapsedSeconds = elapsedTime / 1000; long secondsDisplay = elapsedSeconds % 60; long elapsedMinutes = elapsedSeconds / 60; //put here code to format and display the values 

程序员犯的最大错误就是认为他们需要一个变量来保持当前时间然后编写代码来每秒递增该变量,例如他们维护的称为“elapsedSeconds”的东西。 问题是您可以安排每秒调用代码,但不能保证何时会调用该代码。 如果系统繁忙,则可能比第二个调用的代码要晚一些。 如果系统非常繁忙(例如从故障磁盘中获取页面),实际上可能会延迟几秒钟。 使用Thread.sleep(1000)函数每秒循环的代码将发现错误随着时间的推移而累积。 如果睡眠一次返回300毫秒,则该错误会在计算时间时加以计算。 这完全没必要,因为操作系统具有告诉您当前时间的function

无论您是每秒运行此代码,每秒运行100次还是每3.572秒执行一次,上述计算将是准确的。 关键是currentTimeMillis()是时间的准确表示,无论何时调用此代码 – 这都是一个重要的考虑因素,因为线程和计时器事件不能保证在特定时间是准确的。

计时器的第二个方面是刷新显示器。 这取决于您使用的技术。 在GUI环境中,您需要安排绘制事件。 您希望这些绘制事件在显示预期更改之后立即生效。 但是,这很棘手。 您可以申请油漆事件,但可能有数百个其他油漆事件排队等待您的事件处理。

一种懒惰的方法是每秒安排10个绘制事件。 因为时间的计算不依赖于在特定时间点调用的代码,并且因为如果您在同一时间重新绘制屏幕并不重要,这种方法或多或少地保证了显示的时间将是在大约1/10秒内显示正确的时间。 这看起来有点浪费,因为10次中有9次你正在绘制屏幕上已有的内容。

如果你正在编写一个带有某种动画的程序(如游戏),它每秒刷新30次屏幕,那么你就什么都不做了。 只需将计时器显示调用合并到常规屏幕刷新中即可。

如果绘制事件很昂贵,或者您正在编写执行终端样式输出的程序,则可以通过计算显示将更改之前剩余的时间量来优化事件的计划:

 long elapsedTime = System.currentTimeMillis() - startTime; long timeTillNextDisplayChange = 1000 - (elapsedTime % 1000); 

变量timeTillNextDisplayChange保存您需要等待的秒数,直到计时器的秒部分发生变化。 然后,您可以调度当时发生的绘制事件,可能调用Thread.sleep(timeTillNextDisplayChange)并在睡眠后执行输出。 如果您的代码在浏览器中运行,则可以使用此技术在适当的时间更新页面DOM。

请注意,此计算显示刷新中没有任何内容会影响计时器本身的准确性。 线程可能会迟到10毫秒,甚至迟到500毫秒,并且计时器的准确性不会受到影响。 在每次传递时,我们计算从currentTimeMillis等待的时间,因此一次调用迟到不会导致后期显示延迟。

这是准确计时器的关键。 不要指望操作系统调用您的例程或在您要求时准确发送绘图事件。 通常,当然,对于现代机器,操作系统具有显着的响应性和准确性。 这种情况发生在测试情况下,你没有运行太多其他东西,而计时器似乎工作。 但是,在生产中,在极少的压力情况下,你不希望你的计时器“漂移”,因为系统很忙。

您可以使用java.util Timer类或其他方式,这更复杂,使用Threads。 Timer也有线程动作,但使用它很容易理解。