11

The following code:

long msBefore = System.currentTimeMillis();
//Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
try
{Thread.sleep(200);
} catch (InterruptedException e){}
System.out.println("Time: " + (System.currentTimeMillis() - msBefore));

prints :

Time: 578
Time: 594
Time: 625
Time: 640
Time: 641
Time: 609
Time: 625
Time: 625
Time: 610
Time: 609
Time: 625
Time: 625
Time: 422
Time: 625
Time: 594
Time: 609
Time: 625
Time: 594
Time: 594
Time: 625

Where's the problem??

Muhammad Hewedy
  • 29,102
  • 44
  • 127
  • 219
  • While you are subject to the accuracy of your system, it should much closer than this. On My Windows and Linux systems it is rarely more than 2 ms longer than expected. What OS do you have? – Peter Lawrey May 23 '11 at 12:02
  • Hi Mohammed. As others have pointed out, this will be subject to your systems's accuracy (even environmental factors such as temperature can kick in). Just out of curiosity, what is the actual problem you are trying to solve by this code? Depending upon your answer, someone here might be able to help you with a better way to do it (e.g., a TimerTaskExecutor would be much more accurate for printing regular heartbeats). Please make sure you raise the question in a different thread. Cheers. – Apoorv May 23 '11 at 12:21
  • I've run it several times later, and it is to a great extend accurate now. Thanks All for help. – Muhammad Hewedy May 24 '11 at 08:15

5 Answers5

9

I have a requirement to send n messages per second, I think wait/notify don't fit, correct?

If you have a hard timing requirement, then you are going to need to use a real-time Java implementation. Mainstream SE and ME Java implementations are not suitable for hard realtime applications.

There are various tricks you can use to meet such requirements "most of the time" ... but if your application / system gets overloaded you are liable start to missing the required message rate.

Th real problem is not the accuracy of the timers, but the fact that a non-realtime scheduler won't (and can't) guarantee to schedule the thread to run as soon as the timer expires.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
7

There is no problem here. From javadoc:

subject to the accuracy of system and schedulers.

Usually, it is bad design to rely on the sleeping interval as it can be different on different systems and JVM implementations. Use wait() and notify() instead, or better - use java.util.concurrent package.

Vladimir Ivanov
  • 42,730
  • 18
  • 77
  • 103
  • I have a requirement to send n messages per second, I think wait/notify don't fit, correct? – Muhammad Hewedy May 23 '11 at 10:13
  • 4
    wait/notify uses the same timers as sleep. Its just as accurate. – Peter Lawrey May 23 '11 at 11:59
  • 2
    The real problem is not timer accuracy. The problem is guaranteeing that the thread will be scheduled immediately on the expiry of the timer. That's virtually impossible ... unless you are using a realtime Java on a realtime capable OS. – Stephen C May 24 '11 at 08:42
  • 1
    Timer will not help the case whatsoever. 400ms difference has nothing to do w/ inaccuracy. The code for wait()/notify() and concurrent is no different in terms of accuracy (since it relies on the same OS signals). 400ms just means some other threads keep the process and the thread from taking its own time quant. *Stephen's answer is right on the money* – bestsss May 24 '11 at 09:36
  • sleep is meant to suspend execution on the current thread for at least a specified time, not exactly a specified time. – Charity Leschinski Dec 20 '12 at 18:06
0

If you really need fixed message rate, implement something like a spin-lock. It will consume single CPU core, but get you close.

long nextTime = System.currentTimeMillis() + interval;
while (keepRunning) {
   while (nextTime - System.currentTimeMillis() > 0)
       ;
   sendMessage();
   nextTime += interval;
}
Andy Malakov
  • 797
  • 8
  • 6
0

I'm working with GLFW and get a same problem, I have a solution for this. You can get the difference from sleep time you want and reality and then reduce sleep time.

public void runApp() {
    double begin, end, delta, sleepTime, sleepExtras = 0;

    while (alive) {
        if (appWindow.shouldClose()) break;

        begin = Chronos.currentTime(); // Time in second

        // === RENDER ACTION ===
        appWindow.render();
        // === END RENDER ACTION ===

        glfwPollEvents();

        end        = Chronos.currentTime();
        delta      = end - begin;
        currentFPS = Math.min(1 / delta, lockFPS);
        sleepTime  = Math.max(1.0 / currentFPS - delta - sleepExtras, 0);

        try {
            begin = Chronos.currentTime();
            // IDK why it sleeps with 2 extra milliseconds on my computer =))
            Thread.sleep((long) ((sleepTime) * 1e3));
            end         = Chronos.currentTime();
            delta       = end - begin;
            sleepExtras = delta - sleepTime;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
VN VNA
  • 117
  • 1
  • 7
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 25 '21 at 14:30
  • If you have a new question, please ask it by clicking the [Ask Question](https://stackoverflow.com/questions/ask) button. Include a link to this question if it helps provide context. - [From Review](/review/late-answers/30172578) – Tapan Hegde Oct 25 '21 at 15:38
0

You're not taking into account the time it spends processing.

    try {
        long processingStart = System.currentTimeMillis();

        long processingFinish = System.currentTimeMillis();
        long processTime = 600 - (processingFinish - processingStart);
        Thread.sleep(processTime);

    } catch (InterruptedException ex) {

    }