Точный сон для 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 миллисекунд.
Ответ 9
Похоже, вам нужна реализация в режиме реального времени Java.