Windows 上 Java 的准确睡眠

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/824110/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:54:38  来源:igfitidea点击:

Accurate Sleep for Java on Windows

javawindowssleep

提问by HaBaLeS

Does anyone know a Library which provides a Thread.sleep() for Java which has an error not higher than 1-2 Millisecond?

有谁知道一个为 Java 提供 Thread.sleep() 的库,它的错误不高于 1-2 毫秒?

I tried a mixture of Sleep, error measurement and BusyWait but I don't get this reliable on different windows machines.

我尝试了睡眠、错误测量和 BusyWait 的混合,但在不同的 Windows 机器上我没有得到这个可靠的。

It can be a native implementation if the implementation is available for Linux and MacOS too.

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

EDITThe link Nick provided ( http://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks) is a really good resource to understand the issues all kinds of timers/sleeps/clocks java has.

编辑Nick 提供的链接 ( http://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks) 是一个非常好的资源,可以了解 Java 的各种计时器/睡眠/时钟问题。

采纳答案by Pool

To improve granularity of sleep you can try the following from this Thread.sleeppage.

为了提高睡眠的粒度,您可以从这个Thread.sleep页面尝试以下操作。

Bugs with Thread.sleep() under Windows

If timing is crucial to your application, then an inelegant but practical way to get round these bugs is to leave a daemon thread running throughout the duration of your application that simply sleeps for a large prime number of milliseconds (Long.MAX_VALUE will do). This way, the interrupt period will be set once per invocation of your application, minimising the effect on the system clock, and setting the sleep granularity to 1ms even where the default interrupt period isn't 15ms.

Windows 下 Thread.sleep() 的错误

如果时间对您的应用程序至关重要,那么绕过这些错误的一种不优雅但实用的方法是让守护程序线程在您的应用程序的整个持续时间内运行,该线程只是休眠大量质数毫秒(Long.MAX_VALUE 可以)。这样,每次应用程序调用都会设置一次中断周期,最大限度地减少对系统时钟的影响,并将睡眠粒度设置为 1 毫秒,即使默认中断周期不是 15 毫秒。

The page also mentions that it causes a system-wide change to Windows which may cause the user's clock to run fast due to this bug.

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

EDIT

编辑

More information about this is available hereand an associated bug reportfrom Sun.

此处提供有关此的更多信息 以及来自 Sun的相关错误报告

回答by 1800 INFORMATION

Use one of the Thread::joinoverrideson the current thread. You specify the number of milliseconds (and nanoseconds) to wait.

在当前线程上使用Thread::join覆盖之一。您指定要等待的毫秒数(和纳秒数)。

回答by Daniel Brückner

There are no good reasons to use Thread.sleep()in normal code - it is (almost) always an indication of a bad design. Most important is, that there is no gurantee that the thread will continue execution after the specified time, because the semantics of Thread.sleep()is just to stop execution for a given time, but not to continue immedeately after that period elapsed.

Thread.sleep()在正常代码中使用没有充分的理由- 它(几乎)总是表明设计不佳。最重要的是,没有保证线程会在指定的时间后继续执行,因为 的语义Thread.sleep()只是在给定的时间内停止执行,而不是在该时间段过去后立即继续执行。

So, while I do not know what you try to achieve, I am quite sure you should use a timer instead.

所以,虽然我不知道你想达到什么目的,但我很确定你应该改用计时器。

回答by alphazero

JDK offers the Timer class.

JDK 提供了 Timer 类。

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

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

Reading the docs clearly indicates that beyond the plumbing to make this a generalized framework, it uses nothing more sophisticated than a call to Object.wait(timeout):

阅读文档清楚地表明,除了使这个框架成为通用框架的管道之外,它使用的只是对 Object.wait(timeout) 的调用:

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

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

So, you can probably cut the chase an just use Object#wait yourself.

因此,您可能可以停止追逐,只需自己使用 Object#wait 即可。

Beyond those considerations, the fact remains that JVM can not guarantee time accuracy across platforms. (Read the docs on http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html#currentTimeMillis())

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

I think you'll need to experiment with a compromise solution combining Timer and busy polling if you want to want the highest timing precision possible on your platform. Effectively Object#wait(1) -> System#nanoTime -> calculate delta -> [loop if necessary].

如果您想在您的平台上获得最高的计时精度,我认为您需要尝试结合 Timer 和繁忙轮询的折衷解决方案。有效地 Object#wait(1) -> System#nanoTime -> 计算增量 -> [如有必要,循环]。

If you are willing to roll your own, JNI pretty much leaves it wide open for platform specific solutions. I am blissfully un-aware of Window's internals, but obviously if the host OS does provide sufficiently accurate realtime timer services, the barebones structure of setting up a timerRequest(timedelta, callback) native library shouldn't be beyond reach.

如果您愿意推出自己的产品,JNI 几乎会为特定于平台的解决方案敞开大门。我很高兴不知道 Window 的内部结构,但很明显,如果主机操作系统确实提供了足够准确的实时计时器服务,那么设置 timerRequest(timedelta, callback) 本机库的准系统结构不应该是遥不可及的。

回答by Michael Borgwardt

Sounds like you need an implementation of real-time Java.

听起来您需要一个实时 Java 的实现

回答by Peter Lawrey

You could try using the new concurrency libraries. Something like:

您可以尝试使用新的并发库。就像是:

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

This sleeps between 2.6 and 2.8 milliseconds.

这会在 2.6 到 2.8 毫秒之间休眠。

回答by Peter Lawrey

The Long.MAX_VALUE hack is the working solution.

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

I tried Object.wait(int milis) to replace Thread.sleep, but found that Object.wait is as accurate as Thread.sleep (10ms under Windows). Without the hack, both methods are not suitable for any animation

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

回答by Joao da Silva

This is ~5 months late but might be useful for people reading this question. I found that java.util.concurrent.locks.LockSupport.parkNanos()does the same as Thread.sleep()but with nanosecond precision (in theory), and much better precision than Thread.sleep()in practice. This depends of course on the Java Runtime you're using, so YMMV.

这晚了大约 5 个月,但可能对阅读此问题的人有用。我发现,java.util.concurrent.locks.LockSupport.parkNanos()做同样的Thread.sleep(),但以纳秒精度(理论上),和更好的精度比Thread.sleep()在实践中。这当然取决于您使用的 Java 运行时,所以 YMMV。

Have a look: LockSupport.parkNanos

看一看:LockSupport.parkNanos

(I verified this on Sun's 1.6.0_16-b01 VM for Linux)

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

回答by Andy Malakov

Unfortunately, as of Java 6 all java sleep-related methods on Windows OS [including LockSupport.awaitNanos()] are based on milliseconds, as mentioned by several people above.

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

One way of counting precise interval is a "spin-yield". Method System.nanoTime() gives you fairly precise relative time counter. Cost of this call depends on your hardware and lies somewhere 2000-50 nanos.

计算精确间隔的一种方法是“自旋产量”。方法 System.nanoTime() 为您提供相当精确的相对时间计数器。此调用的成本取决于您的硬件,大约为 2000-50 纳秒。

Here is suggested alternative to Thread.sleep():

这是 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);
    }

This approach has one drawback - during last 2-3 milliseconds of the wait hit CPU core. Note that sleep()/yield() will share with other threads/processes. If you are willing to compromise a little of CPU this gives you very accurate sleep.

这种方法有一个缺点——在等待命中 CPU 内核的最后 2-3 毫秒期间。请注意, sleep()/yield() 将与其他线程/进程共享。如果您愿意牺牲一点 CPU,这将为您提供非常准确的睡眠