Thread.sleep ждет больше, чем ожидалось

Следующий код:

long msBefore = System.currentTimeMillis();
//Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
try
{Thread.sleep(200);
} catch (InterruptedException e){}
System.out.println("Time: " + (System.currentTimeMillis() - msBefore));

печатает:

Time: 578
Time: 594
Time: 625
Time: 640
Time: 641
Time: 609
Time: 625
Time: 625
Time: 610
Time: 609
Time: 625
Time: 625
Time: 422
Time: 625
Time: 594
Time: 609
Time: 625
Time: 594
Time: 594
Time: 625

В чем проблема ??


person Muhammad Hewedy    schedule 23.05.2011    source источник
comment
Хотя вы и зависите от точности вашей системы, она должна быть намного ближе, чем это. В системах My Windows и Linux это редко превышает ожидаемое более чем на 2 мс. Какая у вас ОС?   -  person Peter Lawrey    schedule 23.05.2011
comment
Привет, Мохаммед. Как указывали другие, это будет зависеть от точности вашей системы (могут сказаться даже факторы окружающей среды, такие как температура). Просто из любопытства, какую реальную проблему вы пытаетесь решить с помощью этого кода? В зависимости от вашего ответа кто-то из присутствующих может помочь вам найти лучший способ сделать это (например, TimerTaskExecutor будет намного точнее для печати регулярных ударов сердца). Убедитесь, что вы подняли вопрос в другой цепочке. Ваше здоровье.   -  person Apoorv    schedule 23.05.2011
comment
Я проверял его несколько раз позже, и сейчас он очень точен. Всем спасибо за помощь.   -  person Muhammad Hewedy    schedule 24.05.2011


Ответы (4)


У меня есть требование отправлять n сообщений в секунду, я думаю, что ожидание / уведомление не подходят, верно?

Если у вас есть жесткие требования к времени, вам нужно будет использовать Java в реальном времени. реализация. Обычные реализации Java для SE и ME не подходят для приложений жесткого реального времени.

Существуют различные уловки, которые вы можете использовать для удовлетворения таких требований "большую часть времени" ... но если ваше приложение / система перегружается, вы, скорее всего, начнете пропускать требуемую частоту сообщений.

Настоящая проблема заключается не в точности таймеров, а в том, что планировщик, работающий не в реальном времени, не может (и не может) гарантировать, что поток будет запускаться, как только истечет время таймера.

person Stephen C    schedule 23.05.2011
comment
Спасибо за ссылку и информацию. - person Muhammad Hewedy; 24.05.2011

Здесь нет никаких проблем. Из javadoc:

зависит от точности системы и планировщиков.

Обычно полагаться на интервал ожидания - плохая идея, поскольку он может быть разным в разных системах и реализациях JVM. Вместо этого используйте wait () и notify (), а лучше - пакет java.util.concurrent.

person Vladimir Ivanov    schedule 23.05.2011
comment
У меня есть требование отправлять n сообщений в секунду, я думаю, что ожидание / уведомление не подходят, верно? - person Muhammad Hewedy; 23.05.2011
comment
wait / notify использует те же таймеры, что и режим сна. Это так же точно. - person Peter Lawrey; 23.05.2011
comment
Настоящая проблема не в точности таймера. Проблема заключается в том, чтобы гарантировать, что поток будет запланирован немедленно по истечении таймера. Это практически невозможно ... если только вы не используете Java в реальном времени в операционной системе с поддержкой реального времени. - person Stephen C; 24.05.2011
comment
Таймер ни в коем случае не поможет. Разница в 400 мс не имеет никакого отношения к неточности. Код для wait () / notify () и concurrent не отличается по точности (поскольку он полагается на одни и те же сигналы ОС). 400 мс просто означает, что некоторые другие потоки не позволяют процессу и потоку занимать свой собственный квант времени. Ответ Стивена прямо на деньгах - person bestsss; 24.05.2011
comment
sleep предназначен для приостановки выполнения в текущем потоке по крайней мере на указанное время, а не точно на указанное время. - person Charity Leschinski; 20.12.2012

Вы не учитываете время, затрачиваемое на обработку.

    try {
        long processingStart = System.currentTimeMillis();

        long processingFinish = System.currentTimeMillis();
        long processTime = 600 - (processingFinish - processingStart);
        Thread.sleep(processTime);

    } catch (InterruptedException ex) {

    }
person javaExpert    schedule 26.02.2012

Если вам действительно нужна фиксированная частота сообщений, реализуйте что-то вроде блокировки вращения. Он будет потреблять одно ядро ​​процессора, но вы приблизитесь.

long nextTime = System.currentTimeMillis() + interval;
while (keepRunning) {
   while (nextTime - System.currentTimeMillis() > 0)
       ;
   sendMessage();
   nextTime += interval;
}
person Andy Malakov    schedule 18.06.2012