有没有人知道为Java提供Thread.sleep()的库,其错误不高于1-2毫秒?
我尝试了Sleep,错误测量和BusyWait的混合,但我不能在不同的Windows机器上获得这种可靠性。
如果该实现也适用于Linux和MacOS,它可以是本机实现。
修改 Nick提供的链接(http://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks)是了解java所有定时器/睡眠/时钟问题的非常好的资源。
答案 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。
(我在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的实现。