1

I want a busy wait loop for a specific amount of time and I tested the following java code, which gives different outputs on different runs (sometimes). Most of the time it gives 16 and 0. It means one can not trust a busy wait. What is the reason?

public class Testme {

    public Testme() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000L; i++) {}

        long end = System.currentTimeMillis();

        System.out.println(end - start);
    }

    public static void main(String[] args) {
        new Testme();
    }
}
Andre Hofmeister
  • 3,185
  • 11
  • 51
  • 74
Faisal Bahadur
  • 498
  • 3
  • 19
  • 2
    This style of wait will always be inconsistent as it's work based rather than time based. That aside, `currentTimeMillis()` is probably not as granular as you think it is (don't use it for timing like this). There's also scope for that block to be optimized out completely depending on settings. – AndySavage Nov 13 '15 at 15:57
  • Do you mean that time based busy-wait is always consistent? – Faisal Bahadur Nov 13 '15 at 16:05
  • If you check the time, it will be a lot more consistent than not checking the time. Processing something will take a variable amount of time to process based on the system it's running on. – phflack Nov 13 '15 at 16:08

2 Answers2

0

You definitely can't in such way. Not only that it's unreliable and inconsistent across various processors but can be easily optimized out by JIT.

Zbynek Vyskovsky - kvr000
  • 18,186
  • 3
  • 35
  • 43
0

There is a good chance that your empty for loop will be optimized and removed.

Instead, to pass the time it would be better to use Thread.sleep(long time) inside of a while loop to check and make sure the correct amount of time has passed

long timeToWait = 500;
long startTime = System.currentTimeMillis();
while(startTime + timeToWait > System.currentTimeMillis())
    Thread.sleep(startTime + timeToWait - System.currentTimeMillis());
//do stuff after the .5 second wait

Another way, not as good as Thread.sleep(), is to use a while loop until the correct time

long timeToWait = 500;
long startTime = System.currentTimeMillis();
while(startTime + timeToWait > System.currentTimeMillis());
//do stuff after the .5 second wait

I would also not recommend using a for loop with processing inside to attempt to pass time due to pipelining. The checking statement will fly by super fast once the processor realizes that it's almost always going to be true while processing.

Community
  • 1
  • 1
phflack
  • 2,729
  • 1
  • 9
  • 21
  • Ohh! Thanks God You come to my point yourself. Actually I have used Your code for busy waits of 10ms. I have hundred of jobs of 10ms to process by so many threads ,but the result are so much terrible as many jobs are running less than 10ms even many jobs runs for 0ms. What is the reason? – Faisal Bahadur Nov 13 '15 at 16:10
  • @MuhammadAbdullah Why do you need the timings to be so small? And what happens if you just use `Thread.sleep(10)`? If you use either example with `long timeToWait = 10;`, then it should always wait for at least 10ms, if not more – phflack Nov 13 '15 at 16:14
  • I am not using Thread.sleep(). i am using your second approach ie spin. But many jobs are running less than 10ms. I am so much worried.... – Faisal Bahadur Nov 13 '15 at 16:15
  • Because Win32 API's Sleep isn't a high-precision sleep, and has a maximum granularity. So i decided to use spin. I have so many jobs of 10ms to run but in the result there are some jobs whose turnaroud time is less than 10ms. i have also tried on 100ms but the results are again wrong. I dont know what is the reason? – Faisal Bahadur Nov 13 '15 at 16:25
  • @MuhammadAbdullah How are you testing the time it takes? If you're using `System.currentTimeMillis()`, then it should provide just as accurate results as both methods of waiting for 10ms – phflack Nov 13 '15 at 16:34
  • Sir! i am using this code....long sleepTime = this.delay*1000000L; long startTime = System.nanoTime(); while ((System.nanoTime() - startTime) < sleepTime) {} – Faisal Bahadur Nov 13 '15 at 16:38
  • where delay is 10ms . i also test 100ms but there are still some jobs run less than 100ms – Faisal Bahadur Nov 13 '15 at 16:39
  • Issue has been resolved. I just copied pasted your code and now i am not getting any job running less than the specified time. The only problem is with 10ms jobs which never runs for 10ms but runs for 15 to 16ms. Any how i think this is due to the Thread schedular. Is not it? – Faisal Bahadur Nov 13 '15 at 17:02
  • @MuhammadAbdullah This sounds like an issue with the OS/java interfacing with eachother and not supporting that high of precision. As for using `System.nanoTime()`, it often just returns the same time as `System.currentTimeMillis()` – phflack Nov 13 '15 at 17:58