开发者

Thread.sleep waits more than expected

The following code:

l开发者_JAVA百科ong 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??


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.


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.


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) {

    }


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;
}


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();
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜