5

I'm programming a game in Java and I limit the FPS to 60. I figured out 2 different ways to get the same result, but I'm wondering which of them is the better/cleaner way to do it. Or maybe you have a different idea.

while(System.nanoTime() - thisFrame < fps_limit);

or

Thread.sleep(sleepingTime);

My thinking is that the while loop effects the CPU more than Thread.sleep, am I right?

Thanks in advance for your help!

Dom

Dominik Fuchs
  • 53
  • 1
  • 1
  • 5
  • `Thread.sleep` doesn't sleep for an accurate amount of time. It might sleep for a bit longer; and once the thread wakes up, it might not be running at the same priority as previously. ([More](http://stackoverflow.com/questions/23169557/thread-sleep-and-precise-timing)). – Andy Turner Apr 14 '16 at 15:03
  • If you're aiming for ns precision this won't work, if you're aiming time > 10ms you'll be perfectly fine – Walfrat Apr 14 '16 at 15:12

7 Answers7

3

You have the following main options:

  1. While loop - This will consume CPU cycles and often will actually stop the system because while you are looping, other threads cannot run (on a one-core machine).
  2. Thread.sleep() - This can be effective but you need to remember that is not guaranteed to wait the specified time.
  3. DelayQueue - More up-to-date. Better/accurate timing.
  4. ScheduledThreadPoolExecutor - Still more up-to-date than DelayQueue. Uses a Thread Pool.
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • What do you mean other threads cant run? they are still in your program counter right? – Sven van den Boogaart Apr 14 '16 at 15:28
  • A while loop is a busy wait meaning it will consume processor resources doing nothing...resources and time that could have been used to execute another thread... – MS Srikkanth Apr 14 '16 at 15:39
  • @user3493289 other threads are still in your program counter right? – Sven van den Boogaart Apr 14 '16 at 15:42
  • 1
    What???? Each processor (core) has its own instruction pointer (IP). A busy wait while loop while cause the processor's IP to continue executing the instructions in the while loop (which in this case is an empty while loop). So the processor will continuously loop checking to see if the condition of the while loop is satisfied. Other processors or cores in the machine could eb executing different instructions at the same time but this particular processor will be blocked. – MS Srikkanth Apr 14 '16 at 15:44
  • @user3493289 - If there is only one core then a busy loop can hang the JVM. – OldCurmudgeon Apr 14 '16 at 15:49
  • @user3493289 but other threads can still run right? thats what i ment. I agree it takes unnecessary cpu cycles. – Sven van den Boogaart Apr 14 '16 at 15:49
  • @user3493289 - If you want your code to work in all architectures you should **not** use a wait-loop. Why would you arbitrarily lock yourself out of a family of systems just because you couldn't be bothered to choose a better method? – OldCurmudgeon Apr 14 '16 at 15:52
  • Thread.sleep is also blocking the thread though http://stackoverflow.com/a/8815944/1667868 – Sven van den Boogaart Apr 14 '16 at 15:53
  • @OldCurmudgeon - Why are you even mentioning that to me? When did I suggest using a busy wait loop? Infact I suggested a scheduledthreadPoolExecutor as an answer. It is perhaps SvenB that you want to address. – MS Srikkanth Apr 14 '16 at 15:56
  • 1
    @SvenB - The link you posted was for C#. Java does indeed block on `Thread.sleep()` but only the currently running thread blocks (obviously). It should not block any other threads (busy loop can). – OldCurmudgeon Apr 14 '16 at 15:59
  • @OldCurmudgeon thanks I did not know that, I will edit my answer with the while loop combined with this. – Sven van den Boogaart Apr 14 '16 at 16:03
  • I'm having some trouble in understanding these concepts. One think I thought was, if we put a basic loop inside a if that checks is was passed, e.g., 1 millisecond? Example here: https://pastebin.com/PBwNu8YQ. This prints in my console something over fps: 64; ups: 60. What's the implications of using this? – Lucas Sousa May 15 '20 at 01:00
1

You're right, while both with achieve what you're trying to do, the while loop will keep the processor occupied, consuming CPU time.

In contrast, Thread.sleep() frees the processor for the amount of time mentioned.

So, Thread.sleep() is better.

Ayush Gupta
  • 8,716
  • 8
  • 59
  • 92
1

Both the answers posted already are good - sleep is better than loop. However, you can go into much more detail about how to write a good loop. If you are interested, here is a great resource: http://www.java-gaming.org/index.php?topic=24220.0

It covers topics like variable timestep and interpolation, which can be used to make your graphics run extremely smoothly. This solves the issues Thread.sleep has with not being 100% accurate in its timing as well as preventing your graphics from appearing jerky if your game performs some calculation that takes some time.

nhouser9
  • 6,730
  • 3
  • 21
  • 42
1

What I would do (pseudo code).

//timepast since last loop in ms
timepast = 0
fpslimit = 60
finished = true;
//while the game is running
while(runnning)
{
    timepast += timeSinceLastrun
    if(timepast  > 1second/fpslimit && finished)
    {            
            finished = false    
            dostuff(timepast)
    }
    //sleep for the time of 1second/fpslimit - timepassed to avoid cpu blocking
    Thread.sleep((1second/fpslimit) - timepast )
}

dostuff(deltatime)
{
   //do stuff in the end after it finished set 
   //finished to true so dostuff can be called again
   finished = true
   timepast=0
}

In this way you can easily limit the fps with a variable and dont need to block other threads.

as OldCurmudgeon said thread.sleep dosnt block other threads in java and make processor time available.

Thread.sleep causes the current thread to suspend execution for a specified period. This is an efficient means of making processor time available to the other threads of an application or other applications that might be running on a computer system

Also you can pass timepast to the dostuff method as a deltatime so the game runs the same on all devices (same speed).

Sven van den Boogaart
  • 11,833
  • 21
  • 86
  • 169
0

I concur with @ayush - while loops are usually blocking functions, whereas threads are more like interrupt-driven or parallel programming functions. I'm a bit green on Java, but could you not setup a timer rather than sleeping?

Yeah it looks like Timer constructs, like in C++, are available. Check this out: Timer in Java Thread

Community
  • 1
  • 1
  • in the link(http://www.java-gaming.org/index.php?topic=24220.0) nhouser9 posted they say a Timer is easy to set up and more or less accurate, but the TimerTask should be done quickly. It's enough for AmateurProjects, but not enough for me ;) – Dominik Fuchs Apr 15 '16 at 03:06
0

You should use neither of them. Please take a look at the documentation for ScheduledThreadPoolExecutor

In particular you are looking at this function

ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit)
MS Srikkanth
  • 3,829
  • 3
  • 19
  • 33
  • What if your last loop isnt finished before the next scheduled time? – Sven van den Boogaart Apr 14 '16 at 15:20
  • It means you have underestimated your period and the heavy calculations that you require would necessarily change your fps which would directly affect the period. – MS Srikkanth Apr 14 '16 at 15:24
  • But how do you calculate the minimum? you dont always know the hardware of the user and if his cpu is running alot of different tasks. Could you post some pseudo code im curious how the full game loop would look. – Sven van den Boogaart Apr 14 '16 at 15:25
  • 1
    Take a look at this : http://pastebin.com/zkxeBYy4 When I type it as a comment, it looks weird. – MS Srikkanth Apr 14 '16 at 15:36
-1

while loop will use CPU resource and it is good only if your avg.waiting time is very less and expecting precision.

Thread.sleep() is fine if no precision is expected as CPU priority will change after thread wakes up and it may or may not be scheduled immediately to run and it also should not to be used like this

while(! canContinue()) {
   Thread.sleep(1000);
}

For the above case, alternative is these cases better to use wait()/notify() if you want to suspend the current thread and wait for another thread to process something and then notify the current thread to continue.

some references you can read,

http://tutorials.jenkov.com/java-concurrency/thread-signaling.html

http://www.jsresources.org/faq_performance.html#thread_sleep

lazydev
  • 402
  • 4
  • 16