[java] Thread.sleep

Started by
7 comments, last by H_o_p_s 19 years, 2 months ago
Greetings, this is my very typical game loop (simplified):

        while(running){
	    	startOfLoop = System.currentTimeMillis();
	    	
	    	gameLogic();		
	    	updateGraphics();
	    	
	    	endOfLoop = System.currentTimeMillis();
	    	
	    	loopTime = endOfLoop - startOfLoop;
	    	
	    	while (loopTime < 50){
	    	    try { Thread.sleep(5); } catch (Exception e) {}
	    	    loopTime += 5;
	    	}
        }
As you can see, I'm aiming for 20fps. That's why the inner while-statement checks to see if the looptime is lower than 50ms. If it is, the threads sleeps for 5ms and 5ms are added to the counter, until it's over 50. After experimenting with different sleep values I found that using high values above 20 made the application eat upto 90% of total CPU cycles (I looked it up in the task manager). At 10, this slumped to about 30% and at 5 it's about 15%. I was wondering, why is it, that higher precision requires less CPU time? Is there a way to calculate an ideal value for sleep()? Or should you always use Thread.sleep(1)? I felt uncomfortable with that, thats why I left it at 5. What actually happens inside Thread.sleep()?
Advertisement
You should use Thread.yield() instead.

That way, you get the best performance possible. Thread.sleep(int) has no guarantee that it will return after the gifen time; it only guarantees that it won't be back earlier.

Thread.sleep(int) is for simple, occasional, long time waiting jobs, for example once every 250ms. As soon as "real-time" issues, such as your frame rate, are dependent on the waiting time of your thread, use Thread.yield() instead, and either use the extra time you saved for extra frames (and thus, more smoothness), or quickly check whether enough time has passed, and if not - Thread.yield() again.

A big difference between Thread.yield() and Thread.sleep(int) is that a sleeping thread can be interrupted, raising an InterruptedException. A yielding thread doesn't need to be interrupted, as execution would be resumed ASAP anyway!


Thread.sleep(int) and Thread.yield() both are function calls into the thread management system, where they will simply "draw a number and wait". There are countless implementation-specific details to this, involving spin counts, mutices, and other things that can cause your thread or other threads to wait; and developing a multi-threading system (e.g. the code that makes up "class Thread") is a science all by itself.

instead of trying to slow down the thread, why not just do things when you want it to happen, instead? Check out javax.swing.Timer.

[Formerly "capn_midnight". See some of my projects. Find me on twitter tumblr G+ Github.]

Thanks for the replies, I'll check into Thread.yield() and into Timer to see what suits me best.
@Thygrrr
Thread.yield() takes no parameters and doesn't return a value, so how do I know how long it yields? Do I need to surround it with calls to System.currentTimeMillis(), like with gameLogic() and updateGraphics(), to see if sufficient time has ellapsed to continue, or is there a "smarter" way of using it?
Nanosecond precision is better, and delta is even more better.
So it's either Thread.yield(), or Thread.sleep(20)
Differents OSs have different minimal sleep periode, so you might experience funny results.
Quote:Original post by FiveFootFreak
@Thygrrr
Thread.yield() takes no parameters and doesn't return a value, so how do I know how long it yields? Do I need to surround it with calls to System.currentTimeMillis(), like with gameLogic() and updateGraphics(), to see if sufficient time has ellapsed to continue, or is there a "smarter" way of using it?


Yes, you need to surround it with those calls to determing how long your thread was sleeping. This gives you control on the millisecond level, which is usually enough precision for games.
This might be an issue specific to the UNIX computers I played with for a while, but Thread.sleep(x) where x<5 didn't do anything. I'm pretty sure that's a precision issue, where if it's less than 5 milliseconds, something considers that to be useless and doesn't sleep. I've never had any real problems with it, but it's still not something that I use regularly, so take that with a grain of salt =)
Quote:Original post by FiveFootFreak
	    	while (loopTime < 50){	    	    try { Thread.sleep(5); } catch (Exception e) {}	    	    loopTime += 5;	    	}


Why not just use something like:
[source: java]	public void main_loop(int w) {		WAIT = w;		long START_TIME = 0;		long TOTAL_TIME = 0;		long MILL = 0;		long MILL_WAIT = 0;				while (!done) {			START_TIME = System.currentTimeMillis();			MILL = 1000/WAIT;						update(MILL); //Update our objects, with the given ms						if (System.currentTimeMillis() - START_TIME < MILL) {				drawScreen(); //Draws our objects			}						TOTAL_TIME = System.currentTimeMillis() - START_TIME;			MILL_WAIT = (MILL - TOTAL_TIME);			if (TOTAL_TIME < MILL) {				if (MILL_WAIT > 0) {					try {						Thread.sleep(MILL_WAIT);					} catch (InterruptedException e) {}				}			}		}		System.exit(0);	}WAIT (or w) is how many FPS you wantSTART_TIME is the currentTimeMillis() at the start of the loopMILL is how many ms to wait to get the given FPSTOTAL_TIME is how long in ms to draw the screenMILL_WAIT is how long to Thread.sleep() to get the FPS


Basically you do a this.main_loop(20); to get a 20FPS
And this way the Thread doesn't wake up every 5ms to see if it should sleep again.
BRING BACK THE BLACK (or at least something darker)

This topic is closed to new replies.

Advertisement