Точный сон для Java в Windows

Кто-нибудь знает библиотеку, которая предоставляет Thread.sleep() для Java, которая имеет ошибку не выше 1-2 миллисекунды?

Я попробовал смесь Sleep, измерения ошибок и BusyWait, но я не получаю это надежным на разных машинах Windows.

Это может быть естественная реализация, если реализация также доступна для Linux и MacOS.

ИЗМЕНИТЬ Ссылка Nick предоставлена ​​(http://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks) - действительно хороший ресурс для понимания проблем, связанных со всеми типами таймеров/сон/часов java.

Ответы

Ответ 1

Чтобы улучшить детализацию сна, вы можете попробовать следующее из Thread.sleep.

Ошибки с Thread.sleep() под Windows

Если время имеет решающее значение для вашего приложения, то неэлегантное, но практический способ обойти эти ошибки заключается в том, чтобы запустить поток демона на протяжении всей вашей приложение, которое просто спит для большое простое число миллисекунд (Long.MAX_VALUE будет делать). Сюда, период прерывания будет установлен один раз за вызов вашей заявки, минимизация влияния на систему часы и установка сна гранулярность до 1 мс, даже если период прерывания по умолчанию не равен 15 мс.

На странице также упоминается, что она вызывает общесистемное изменение Windows, которое может привести к быстрому выполнению пользовательских часов из-за этой ошибки .

ИЗМЕНИТЬ

Дополнительная информация об этом доступна здесь и связанный отчет об ошибке от Sun.

Ответ 2

Это примерно на 5 месяцев, но может быть полезно для людей, читающих этот вопрос. Я обнаружил, что java.util.concurrent.locks.LockSupport.parkNanos() делает то же самое, что и Thread.sleep(), но с точностью до наносекунд (теоретически) и гораздо лучшей точностью, чем Thread.sleep() на практике. Это, конечно же, зависит от используемого Java-исполнения, поэтому YMMV.

Посмотрите: LockSupport.parkNanos

(я проверял это на Sun 1.6.0_16-b01 VM для Linux)

Ответ 3

К сожалению, с Java 6 все java-методы, связанные со сном в ОС Windows [в том числе 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);
    }

Этот подход имеет один недостаток - в течение последних 2-3 миллисекунд ядра ядра с ожиданием. Обратите внимание, что sleep()/yield() будет совместно использовать другие потоки/процессы. Если вы хотите скомпрометировать немного процессора, это даст вам очень точный сон.

Ответ 4

Нет никаких веских причин использовать Thread.sleep() в нормальном коде - это (почти) всегда показатель плохой конструкции. Самое главное, что нет гарантии того, что поток продолжит выполнение по истечении указанного времени, потому что семантика Thread.sleep() заключается в том, чтобы остановить выполнение в течение заданного времени, но не продолжать сразу после этого периода.

Итак, пока я не знаю, чего вы пытаетесь достичь, я уверен, что вы должны использовать таймер вместо этого.

Ответ 5

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 # wait.

Помимо этих соображений, остается фактом, что JVM не может гарантировать точность времени на всех платформах. (Прочитайте документы на http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html#currentTimeMillis())

Я думаю, вам нужно поэкспериментировать с компромиссным решением, сочетающим таймер и занятый опрос, если вы хотите, чтобы на вашей платформе была установлена ​​максимальная точность. Эффективно Объект # wait (1) → System # nanoTime → вычисляет delta → [loop при необходимости].

Если вы готовы бросить свой собственный, JNI в значительной степени оставляет его широко открытым для решений на платформе. Я блаженно не осведомлен о внутренних компонентах Window, но, очевидно, если хост-система предоставляет достаточно точные услуги таймера реального времени, структура barebones для настройки встроенной библиотеки timerRequest (timedelta, callback) не должна быть недоступна.

Ответ 6

Ручка Long.MAX_VALUE - это рабочее решение.

Я попробовал Object.wait(int milis) заменить Thread.sleep, но обнаружил, что Object.wait так же точна, как Thread.sleep(10 мс под Windows). Без взлома оба метода не подходят для любой анимации

Ответ 7

Используйте один из Thread::join переопределяет в текущем потоке. Вы указываете количество миллисекунд (и наносекунд) для ожидания.

Ответ 8

Вы можете попробовать использовать новые библиотеки concurrency. Что-то вроде:

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 миллисекунд.