Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

while(true) loop or java.util.Timer for a standard program loop?

Lately I made a very basic program. A time counter which has the ability of pausing. It was working with 3 threads, 2 for Swing and 1 for the main thread.

For this program there should be a delta time counting part in the main thread. I made a very basic system like that;

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));
    }
}

This code above caused high CPU usage. I then replaced that code chunk with:

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);

And the problem was gone. I just wonder the reason of that. Also what is the optimum way of creating a program loop?

like image 825
iGoodie Avatar asked May 06 '16 06:05

iGoodie


2 Answers

Your 1st code block basically runs at the speed of the CPU. To understand that, you'll need to know what IPS and FLOPS are. A modern CPU does a few GFLOPS which means your 1st block is getting executed tens or even hundreds of thousand times per second depending on your hardware. If you run it on the main thread, it will block your UI(i.e. your GUI will get stuck). On a separate thread, it will run continuously taking up resources without actually doing much.

The second block, on the other hand has specific instructions to execute every millisecond. This means that your code block is executed 1000 times and the rest of the cpu time is freed up for other work.

To address the question in your comment: it is almost never acceptable to use an infinite loop. Loops are best used for a bounded repeat of a set of instructions. In your example, it seems like you want to call save every 1000ms and also count session time. I would

  1. separate the save out to a repeating timer that is called every 1000ms.
  2. Create an onSessionPause and onSessionResume which only when the pause-state changes. This could be due to a pause button or some other sort of condition that you define. The onSessionPause and onSessionResume functions should be able to record the time at which they are called and update sessionMs based on the difference in time.

Unless you're expecting things to change every millisecond, you're making the CPU do unnecessary work.

like image 104
nosh Avatar answered Oct 11 '22 14:10

nosh


Also what is the optimum way of creating a program loop?

In your specific case, the optimum way would be a loop running once every second, since this would achieve your goal with minimal CPU usage. As this is impossible to guarantee, you need to find a threshold low enough, so your loop is executed at least once every second, and not too low, to be efficient. I'd suggest you test with some output.

Be carefull though, different code has different requirements, so there is no general optimum way to loop through code. As a basic rule, you should try to avoid as many redundant executions as possible.

like image 33
Raijen Avatar answered Oct 11 '22 12:10

Raijen