Jump to content
  • Advertisement
Sign in to follow this  
EpicWally

Timer vs. thread.sleep();

This topic is 2231 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am new to Java (and OOP in general) and have recently been trying my hand at programming some basic games. My first two attempts used a Timer, with an ActionListener to call for game updates, which seemed to work pretty smoothly (granted these games only used a text interface.) In preparing for my most recent game (a breakout clone) I noticed another user on the forum using a sleep() inside a game thread. My initial observations of this in both his game, and in my own when I implemented it, was that the speed didn't feel constant, like the game would randomly speed up and slow down, presumably on processor load. Is this just a problem with implementation? Which is the preferred method, Timers, or threads? If it is threads, which my gut feel seems to be, how would you avoid this problem? Should the game thread that updates movement etc be a separate thread than the one that calls for screen refreshes?

Thank you for the guidance.

Share this post


Link to post
Share on other sites
Advertisement
Sleep should only be used as a way to preserve the battery on mobile devices (Which tend to behave far better when sleeping aswell), you could include a laptop mode that sleeps for a short period of time after each update if your game is playable that way (don't rely on it to control the speed at which the application runs though), For a desktop game you should preferably grab the system time in your main loop. (updating via actionlisteners and Timer objects is quite a wierd way to go about things but that works aswell)

Keep things in a single thread until you absolutely have to use more.


System.nanoTime() should give you the most accurate timer for your platform. Edited by SimonForsman

Share this post


Link to post
Share on other sites
Sleep should only be used as a way to preserve the battery on mobile devices (Which tend to behave far better when sleeping aswell)
Could you explain why? Although I admittedly don't know how Java implements timers, doing so in any other way than using the timer functionality built into the operating system would be quite dumb, to be honest.

Blocking on a timer and blocking on sleep should be exactly the same in respect of CPU cycles and power consumption. Except that on at least one major operating system (Windows), blocking on a timer has a much better precision and reliability than sleeping. Sleeping will give away the remainder of the time slice and not schedule the thread again before some time, rounded up to the next 16 or so milliseconds. Blocking on a timer puts the thread on the ready list the moment the timer expires and dynamically boosts the thread priority, scheduling it before other and possibly interrupting running threads with the same (original) priority. That's a difference between "yeah, some time, eventually" and "as soon as we can handle it".

Share this post


Link to post
Share on other sites
Hmm, thank you for the tips. So your reccomendation would be to do something to the effect of:

while(playing){
currentTime = System.currentTimeMillis();
if(currentTime > lastTime + updateFrequency){
lastTime = currentTime;
update();
render();
//other game code here
}
}

Did I understand your suggestion correctly? This still looks like it has a potential (albeit small one) for the update frequency to not always be perfect (granted, each cycle where the if statement is false should not take long, so I would doubt you would overshoot your preferred update frequency by more than a ms or two.)

Another thought I had, between posting this and now, would be along a similar line, but still using sleep would do something like:

while(playing){
update();
render();
long currentTime = System.currentTimeMillis();
long sleep = updateFrequency - (currentTime - lastTime);
try{
Thread.sleep(sleep);
}catch(Exception e){}
long lastTime = System.currentTimeMillis();
}

This would allow your delay between cycles to scale based on how long each cycle took, preserving a constant time between cycles (as long as your cycles weren't taking more time than your updateFrequency, which could bugger things up.) I know you said sleep is not the best option, but do you think this would work? My gut feel is that this is cleaner, as your thread is only running when it needs to (once every update cycle) instead of running constantly, continuously checking the system time when it doesn't need to. Not that it's a big overhead. Again, pretty new to this. Just trying to get a good understanding of the pros and cons to all of the possible approaches.

Thanks again for your advice.
-Wally


Edit: I just tried the second idea I mentioned above, and it had the desired effect. I don't know if in a bigger game this would still work as well, or if it only seems to work because of the simplicity of the game. Edited by EpicWally

Share this post


Link to post
Share on other sites

Sleep should only be used as a way to preserve the battery on mobile devices (Which tend to behave far better when sleeping aswell).


This is not totally true. I will give you a quote from the book 'killer game programming in java'

"sleep() causes the animation thread to stop executing, which frees up the CPU for other taks, such as garbage collection by the JVM. without a period of sleep, the GamePanel thread could hog all the CPU time"

I mainly sleep to keep a constant FPS, there are many ways to do this, but the amount of time Thread.sleep() should sleep for, should not be a constant number, that's probably why you had that laggy feeling effect.


This book is a good one and I would recommend it.

Share this post


Link to post
Share on other sites
this is more of a Time-Step problem, http://gafferongames.com/game-physics/fix-your-timestep/

In short, your attempting to run your game at a fixed rate, as such, you need some mechanism to ensure that the frequency continues at a consistant rate(and that your targeted hardware is capable of performing at that rate).

Thread sleep is not reliable the way timers are, most modern hardware can switch back to your thread in ~15ms, but by no means is that set in stone, nor should you rely on that to exist. you can use sleep if you use a proper time-step code, but do remember that sleep is more-so for saving battery power, then to be used as a reliable timer system.

Share this post


Link to post
Share on other sites
I've had pretty good results with Thread.sleep() but I haven't tried using a timer so I can't speak about that.

I had a 2D game with a top-down view (like Zelda LttP or Pokemon) and I've ran it for 45 minutes to an hour with 0 frames lost at 30 frames (and game.updates()) per second. Haven't tried it any higher but that's only because I don't have a reason to.

Share this post


Link to post
Share on other sites
Could you explain why? Although I admittedly don't know how Java implements timers, doing so in any other way than using the timer functionality built into the operating system would be quite dumb, to be honest.

Blocking on a timer and blocking on sleep should be exactly the same in respect of CPU cycles and power consumption. Except that on at least one major operating system (Windows), blocking on a timer has a much better precision and reliability than sleeping. Sleeping will give away the remainder of the time slice and not schedule the thread again before some time, rounded up to the next 16 or so milliseconds. Blocking on a timer puts the thread on the ready list the moment the timer expires and dynamically boosts the thread priority, scheduling it before other and possibly interrupting running threads with the same (original) priority. That's a difference between "yeah, some time, eventually" and "as soon as we can handle it".
[/quote]

Sleep just wraps the OS sleep function, which means your 1ms sleep could end up taking 10+ ms on Windows (it works for some games but for 60fps it will reduce the players experience, which is why i only recommend it as an option, on Android OTOH sleep can be used to control runspeed(in foreground activities) without much problems (It seems to wake up the exact millisecond you asked for each time)).

Timers (as in the Timer class) in Java work reasonably well (on some platforms, i havn't actually tried them on Windows in a very long time), their problem is that they spawn a new thread, they don't touch the currently running thread. There are two classes named Timer in Java (big wtf imo), one in Swing which uses ActionListeners (These are the ones the OP are using) , these create a new thread per timer object and the execution frequency is set per Timer, They have some synchronization overhead since the actual execution is done in the gui thread, not the Timer objects thread). (The actionListener is called by the swing event loop when it encounters the event sent by the Timer object, so even if the event is sent on time it will never be executed on time(Allthough the eventloop runs fast enough i guess)). (Swing imo is a piece of shit API, GUI apps in Java are better off using for example wxWidgets or QT, Games benefit more by using for example LWJGL or Slick.

The second Timer class is in util and uses TimerTasks , these also create a background thread per Timer but can have multiple scheduled tasks(With different frequencies or delays) per Timer, these tasks are executed sequentially. (the util Timer has lower overhead and is more flexible but executes in its own Thread which means you will have to be a bit careful, These are solid enough imo to be used in a game, but the multithreading issues doesn't make them all that suitable for a beginner and they're far better for triggering infrequent events.

Neither Timer class give any realtime guarantees, the spec makes it entierly valid for a compliant VM to implement the Timer classes with far worse accuracy than sleep aswell.

The Timer classes also only have millisecond precision at best, (in practice it is worse than that), System.nanoTime is required to always use the most precise timer available on the underlying platform and normally has very high accuracy. (IIRC it uses QPC on Windows) Edited by SimonForsman

Share this post


Link to post
Share on other sites
Ugh... spawning an extra thread per timer to implement something that can be wrapped in one or two syscalls from the original thread on pretty much every system is really one of the dumbest things I've heard in a while. Thank you for clearing that one up. smile.png

In that case you are of course entirely right, timers are not well suited here.

Share this post


Link to post
Share on other sites

Ugh... spawning an extra thread per timer to implement something that can be wrapped in one or two syscalls from the original thread on pretty much every system is really one of the dumbest things I've heard in a while. Thank you for clearing that one up. smile.png

In that case you are of course entirely right, timers are not well suited here.


I don't think its that dumb, the util Timer class works fairly well for scheduling the execution of independent Tasks(TimerTask objects) (you can schedule multiple tasks per Timer(Allthough a timer can only execute one task at the time) and the Timer thread most likely will use the appropriate OS functions to avoid hogging the CPU while waiting (Allthough the language spec doesn't require any form of accuracy or precision so a VM could just aswell use sleep and still be compliant), The Swing Timer class is a bit more messy with its ActionListener crap but all of Swing is that way(You don't access events directly, you always create a listener(KeyListener, ActionListener, FocusListener, CaretListener, WtFListener, etc) and attach it to a UI component to handle events sent to that component) so the Swing Timer fits nicely with the rest of the API, (I really do hate Swing though and don't think it is suitable for games)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!