Windows上的Java准确睡眠

时间:2009-05-05 09:40:26

标签: java windows sleep

有没有人知道为Java提供Thread.sleep()的库,其错误不高于1-2毫秒?

我尝试了Sleep,错误测量和BusyWait的混合,但我不能在不同的Windows机器上获得这种可靠性。

如果该实现也适用于Linux和MacOS,它可以是本机实现。

修改 Nick提供的链接(http://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks)是了解java所有定时器/睡眠/时钟问题的非常好的资源。

9 个答案:

答案 0 :(得分:17)

要提高睡眠粒度,您可以在此Thread.sleep页面中尝试以下操作。

  

Windows下的Thread.sleep()错误

     

如果时间对你的时间至关重要   应用程序,然后是一个不优雅的但是   绕过这些错误的实用方法   是让一个守护程序线程运行   在你的整个过程中   简单地睡觉的应用程序   大素数毫秒   (Long.MAX_VALUE会这样做)。这条路,   中断周期将设置一次   每次调用你的申请,   最小化对系统的影响   时钟,并设置睡眠   粒度到1ms即使在哪里   默认中断周期不是15ms。

该页面还提到它会导致系统范围内的Windows更改,这可能导致用户的时钟因此bug而快速运行。

修改

有关此内容的更多信息 来自Sun的here和相关的bug report

答案 1 :(得分:11)

这已经晚了5个月,但对于阅读这个问题的人来说可能会有用。我发现java.util.concurrent.locks.LockSupport.parkNanos()Thread.sleep()的作用相同,但在理论上具有纳秒精度,并且在实践中比Thread.sleep()精确得多。这当然取决于你正在使用的Java Runtime,所以YMMV。

看看:LockSupport.parkNanos

(我在Sun的1.6.0_16-b01 VM for Linux上验证了这一点)

答案 2 :(得分:8)

不幸的是,从Java 6开始,Windows OS上的所有与Java睡眠相关的方法[包括LockSupport.awaitNanos()]都基于毫秒,如上面几个人所提到的。

计算精确间隔的一种方法是“旋转屈服”。方法System.nanoTime()为您提供相当精确的相对时间计数器。这次通话的费用取决于你的硬件,大约是2000-50纳米。

这是Thread.sleep()的替代方法:

   public static void sleepNanos (long nanoDuration) throws InterruptedException {
        final long end = System.nanoTime() + nanoDuration;
        long timeLeft = nanoDuration;
        do {
            if (timeLeft > SLEEP_PRECISION)
                Thread.sleep (1);
            else
                if (timeLeft > SPIN_YIELD_PRECISION)
                    Thread.yield();

            timeLeft = end - System.nanoTime();
        } while (timeLeft > 0);
    }

这种方法有一个缺点 - 在等待命中CPU核心的最后2-3毫秒内。请注意,sleep()/ yield()将与其他线程/进程共享。如果你愿意妥协一点CPU,那么你就会very accurate sleep

答案 3 :(得分:4)

在正常代码中使用Thread.sleep()没有充分的理由 - 它(几乎)始终表示设计不良。最重要的是,没有保证线程将在指定时间后继续执行,因为Thread.sleep()的语义只是停止执行给定时间,但是在该时间段过后不能继续执行。< / p>

所以,虽然我不知道你想要达到的目标,但我确信你应该使用计时器。

答案 4 :(得分:4)

JDK提供Timer类。

http://java.sun.com/j2se/1.5.0/docs/api/java/util/Timer.html

阅读文档清楚地表明,除了管道之外,使其成为一个通用框架,它使用的不比调用Object.wait(timeout)更复杂:

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#wait(long)

所以,你可以切断追逐只是使用Object#等你自己。

除了这些考虑因素之外,事实仍然是JVM无法保证跨平台的时间准确性。 (阅读http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html#currentTimeMillis()

上的文档

如果您想要在您的平台上实现最高的计时精度,我认为您需要尝试将计时器和繁忙轮询相结合的折衷解决方案。有效地对象#wait(1) - &gt; System#nanoTime - &gt;计算delta - &gt; [必要时循环]。

如果您愿意自己动手​​,JNI几乎可以为平台特定的解决方案敞开心扉。我很幸福没有意识到Window的内部,但很明显,如果主机操作系统确实提供了足够准确的实时计时器服务,那么设置timerRequest(timedelta,回调)本机库的准系统结构应该是无法实现的。

答案 5 :(得分:3)

Long.MAX_VALUE黑客是可行的解决方案。

我尝试使用Object.wait(int milis)替换Thread.sleep,但发现Object.wait与Thread.sleep一样准确(Windows下为10ms)。没有hack,这两种方法都不适合任何动画

答案 6 :(得分:1)

在当前主题上使用Thread::join overrides之一。您可以指定要等待的毫秒数(和纳秒数)。

答案 7 :(得分:1)

您可以尝试使用新的并发库。类似的东西:

private static final BlockingQueue SLEEPER = new ArrayBlockingQueue(1);
public static void main(String... args) throws InterruptedException {
    for(int i=0;i<100;i++) {
        long start = System.nanoTime();
        SLEEPER.poll(2, TimeUnit.MILLISECONDS);
        long time = System.nanoTime() - start;
        System.out.printf("Sleep %5.1f%n", time/1e6);
    }
}

这睡眠时间在2.6到2.8毫秒之间。

答案 8 :(得分:0)

听起来你需要real-time Java的实现。