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

时间:2012-05-30 16:05:40

标签: java timer

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

3 个答案:

答案 0 :(得分:22)

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

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

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

  1. 计算时间
  2. 刷新显示屏
  3. 计算显示时间所需要做的就是记录计时器开始的时间:

    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毫秒,则该错误会在计算时间时复杂化。这完全没必要,因为OS 具有告诉您当前时间的功能

    无论您是每秒运行此代码,每秒运行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等待的时间,因此一次调用迟到不会导致以后的显示延迟。

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

答案 1 :(得分:0)

您可以使用Timer中的java.util类,也可以使用更复杂的Threads方法。计时器也具有线程操作,但是使用它很容易理解。

答案 2 :(得分:0)

要根据您的需要创建一个简单的计时器,为此编写代码非常容易。我已经编写了以下代码供您参考。如果您希望可以增强它。

import java.util.concurrent.TimeUnit; 公共类PerfectTimer {

public static void main(String[] args) throws InterruptedException 
{
    boolean x=true;
    long displayMinutes=0;
    long starttime=System.currentTimeMillis();
    System.out.println("Timer:");
    while(x)
    {
        TimeUnit.SECONDS.sleep(1);
        long timepassed=System.currentTimeMillis()-starttime;
        long secondspassed=timepassed/1000;
        if(secondspassed==60)
        {
            secondspassed=0;
            starttime=System.currentTimeMillis();
        }
        if((secondspassed%60)==0)
        displayMinutes++;

    System.out.println(displayMinutes+"::"+secondspassed);
    }

}

}