while(true)循环或java.util.Timer用于标准程序循环



最近我做了一个非常基本的程序。一种具有暂停功能的计时器。它使用3个线程,2个用于Swing,1个用于主线程。

对于这个程序,应该在主线程中有一个增量时间计数部分。我制定了一个非常基本的系统;

while(true)
{
    long now = System.currentTimeMillis();
    if(!sessionPaused)
    {
        if(now-programLastMs>1000)
        {
            save();
            programLastMs = now;
        }
        sessionMs += now-sessionPrevMs;
        overallMs += now-sessionPrevMs;
        sessionPrevMs = now;
        sessionLabel.setText(formatMillis("This Session:<br/>",sessionMs));
        overallLabel.setText(formatMillis("Overall:<br/>", overallMs));
    }
}

上面的代码导致CPU使用率高。然后我将该代码块替换为:

timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                long now = System.currentTimeMillis();
                if(!sessionPaused)
                {
                    if(now-programLastMs>1000)
                    {
                        save();
                        programLastMs = now;
                    }
                    sessionMs += now-sessionPrevMs;
                    overallMs += now-sessionPrevMs;
                    sessionPrevMs = now;
                    sessionLabel.setText(formatMillis("This Session:<br/>",sessionMs));
                    overallLabel.setText(formatMillis("Overall:<br/>", overallMs));
                }
            }
        }, 0, 1);

问题已经过去了。我只是想知道为什么。此外,创建程序循环的最佳方式是什么?

您的第一个代码块基本上以CPU的速度运行。要理解这一点,您需要了解IPS和FLOPS是什么。一个现代的CPU会执行一些GFLOPS,这意味着你的第一个块每秒会被执行几十甚至几十万次,这取决于你的硬件。如果你在主线程上运行它,它会阻塞你的UI(即你的GUI会被卡住)。在一个单独的线程上,它将持续运行,占用资源,而实际上没有做太多工作。

另一方面,第二个块具有每毫秒执行一次的特定指令。这意味着您的代码块被执行1000次,其余的cpu时间被释放用于其他工作。

为了解决您评论中的问题:使用无限循环几乎是不可接受的。循环最适合用于一组指令的有界重复。在您的示例中,您似乎希望每1000ms调用save,同时计算会话时间。我会

  1. 将保存分离到一个重复计时器,该计时器每1000ms调用一次
  2. 创建一个onSessionPause和onSessionResume,仅当暂停状态更改时。这可能是由于暂停按钮或您定义的某种其他条件造成的。onSessionPause和onSessionResume函数应该能够记录调用它们的时间,并根据时间差更新sessionMs

除非你期望每毫秒都会发生变化,否则你会让CPU做不必要的工作。

此外,创建程序循环的最佳方式是什么?

在您的特定情况下,最佳方式是每秒运行一次循环,因为这将以最低的CPU使用率实现您的目标。由于这是不可能保证的,您需要找到一个足够低的阈值,因此您的循环至少每秒执行一次,并且不要太低,以提高效率。我建议你用一些输出进行测试。

不过要小心,不同的代码有不同的要求,所以没有通用的最佳方式来循环代码。作为一条基本规则,您应该尽量避免重复执行。

最新更新