aspose file tools*
The moose likes Threads and Synchronization and the fly likes Why my program works fine when i write Thread.sleep(0) Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Threads and Synchronization
Bookmark "Why my program works fine when i write Thread.sleep(0)" Watch "Why my program works fine when i write Thread.sleep(0)" New topic
Author

Why my program works fine when i write Thread.sleep(0)

Jigar Naik
Ranch Hand

Joined: Dec 12, 2006
Posts: 759
Hi,

I have below program which performs some task after every one minutes. Below is my program



output



As you can see the seconds are getting repeated.. which shouldn't get repeated... but if i uncomment the Thread.sleep(0) line the program works just perfectly fine. it executes the task accurately after every 1 second.

What could be the possible reason ? Will my program ever work fine without Thread.sleep(0); ???


Jigar Naik


Martin Vajsar
Sheriff

Joined: Aug 22, 2010
Posts: 3611
    
  60

Well, this is tricky. I'll try to explain it thoroughly.

First of all, the precision of a system timer is not one millisecond, it may be substantially higher. Let's assume that the precision of your system timer is the same as mine - 15 milliseconds. That means that the value of System.currentTimeMillis() changes only once every 15 ms, about 66 times per seconds.

The for-loop (line 21) runs for ten thousand iterations or for one second, whichever comes first. Java is pretty fast nowadays and when there is no sleep() in the for-loop (line 22 commented out), the for-loop actually completes not only faster than one second, but well under 15 ms, so fast that the value of the system timer does not change.

Because the value of the system timer didn't change while the loop was executed, the value of the exeTime variable is 0 (zero). The sleepTime has then a value of 1000. The sleep() at line 32 does not execute when the sleepTime is 1000 (see the condition above), so the method continues with printStat() and then task() is called again, causing the process to repeat (more on this later).

As the for-loop runs well below 15 ms, this whole cycle can be repeated several times during one 15 ms interval, causing multiple printouts with the same second. Just when the for-loop starts close to the end of the 15 ms interval, the system timer changes before the loop completes. At this moment the exeTime will be equal to the value of system timer precision (15 ms). The sleepTime is then computed as 1000 - 15 = 985, and the sleep() at line 32, which is now allowed by the condition on line 31, pauses the execution for the rest of the second. The printStat() called in this iteration will probably write a new second on the screen.

What changes when Thread.sleep(0) is called? The Thread.sleep() is more time consuming operation than, for example, an addition or a simple method call. Executing it 10000 times takes more time than 15 ms, the resolution of the timer (it's actually between 30 and 45 ms on my system). This means that the value of the system timer is guaranteed to change while the for-loop is executing and therefore the exeTime will be nonzero. Consequently sleepTime is less than 1000, allowing the Thread.sleep() at line 32 to pause the execution for the rest of the second. Therefore printStat() is called roughly once per second in this case.

(My computer is probably faster than yours - I get dozens of printouts with the same second. It is also possible that the for-loop with Thread.sleep(0) takes more than one second on your system, in which case it is aborted by the break, and sleepTime is then <= 0. The end result is the same - about one call to printStat() every second.)

Modify your program so that it prints the values of exeTime and sleepTime before the printStat() call and you'll quite clearly see all this happening.


This whole enterprise is unnecessary to achieve your goal. If you need to pause the execution for a second, just call Thread.sleep(1000). If you're not doing time-critical operations (eg. playing a video file), you may probably well ignore the additional time it will take to do the processing. No one will ever notice.

However, there is another serious bug in your code. You made an infinite loop by calling the task() method recursively. This will inevitably lead to an StackOverflowError exception. Try it - comment out lines 15 to 34 in your code, the exceptions appears immediately.

Your task() method should therefore look like this:That's probably all you need.
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 19064
    
  40

Martin Vajsar wrote:
However, there is another serious bug in your code. You made an infinite loop by calling the task() method recursively. This will inevitably lead to an StackOverflowError exception. Try it - comment out lines 15 to 34 in your code, the exceptions appears immediately.


Agreed. Using tail recursion instead of a loop is a really bad thing -- especially since it is a endless loop. Maybe in the future, there will be an optimization that will convert tail recursion to loops, but in the meantime... don't do it.

The other no-no is spin waits. Don't do spin waits. You are eating up precious CPU cycles telling the computer to do nothing useful.

Henry


Books: Java Threads, 3rd Edition, Jini in a Nutshell, and Java Gems (contributor)
Jigar Naik
Ranch Hand

Joined: Dec 12, 2006
Posts: 759
thanks martin for such detail explanation...

but what is the alternative to avoid the recursive loop ? i am also looking for the alternative. my requirement is like i need to send N # of messages in a second. and if i finish # N no of messages in 100 ms remaining 900 ms the program will remain idle.

and suppose if N = 1000 and my program is able to send only 900 in 1 second remaining 100 messages should be discarded.

What are the alternative ? and which one is the best way ? i can use only J2SE 1.5 API.
Martin Vajsar
Sheriff

Joined: Aug 22, 2010
Posts: 3611
    
  60

To avoid the recursion, use the endless loop as I have already shown you.

However, for this kind of processing you could probably use the java.util.concurrent.ScheduledThreadPoolExecutor class. This class will run your tasks at one second intervals as precisely as your system permits. You'll also no longer need the endless loop. See the documentation of this class.

You will still need to limit the processing of a single batch to under one second. You probably should store the value of System.nanoTime() at the beginning of processing (again, see the documentation) and then check after each message that the elapsed time didn't exceed one second, and break if it did. It would actually be quite similar to the your for-loop in your first post, just add the code for posting a message.

Remember that Java is not a real-time system. Depending on a target platform and various other factors, such as garbage collector, your thread could be preempted in the middle of the processing and might at times process much less messages than would be usual. Nothing can be done to prevent this.

Anyway your requirements seem strange to me. Messages that were not posted within a second would be discarded without further notice? There were not that important after all. Hope you're not building a spam server, there is more than enough of them already...
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Why my program works fine when i write Thread.sleep(0)