5

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?

7
  • 3
    Your while(true) loop doesn't make any pause, so the loop is constantly running and constantly eating CPU. The scheduling makes your run method execute, only when it is scheduled to. Commented May 6, 2016 at 6:57
  • So if I made the scheduler call it like once per 50 nanoseconds, would it be the same? And still what is the optimum way of creating a program loop? @Berger Commented May 6, 2016 at 7:04
  • It depends on the duration of your run method, but 50 nanoseconds is really low, do you need such a high frequency ? However as you have seen it, it is better to let your application breathe, so either use a scheduler, or add a Thread.sleep to your while loop. Commented May 6, 2016 at 7:13
  • You also should not block the Swing thread. If you do a long/endless loop in event processing method your program cann not be repainted. Please read about concurrency in swing Commented May 6, 2016 at 7:15
  • So basically Thread.sleep(1) in while(true) loop would have the same effect with Timer? @Berger Commented May 6, 2016 at 7:17

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

That was the perfect answer I was looking for. Thanks for the detailed information (Y)
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.