Почему переход с бесконечного цикла на TimerTask привел к снижению производительности процессора?
Я написал демона, который был структурирован следующим образом:
while( true ) {
// do some stuff
Thread.sleep( 1000 );
}
Я заметил, что он использует очень большой объем процессора - до 100%. У меня был аналогичный демон на моих производственных серверах в течение нескольких месяцев с той же проблемой ЦП.
Вчера я реорганизовал код для использования TimerTask. Сразу же я заметил, что использование ЦП уменьшилось в моем блоке dev. Поэтому я решил развернуть производство и дважды проверить с помощью Munin. Вот графики:
![Load average]()
![CPU usage]()
Несколько пунктов:
- На рабочем сервере нет ничего, кроме JVM.
- Других потоков приложений нет.
- Он определенно выполнял код старого стиля с правильными периодическими интервалами - я всегда записываю журнал каждый раз, когда поток выполняется.
Итак: почему Thread.sleep настолько неэффективен по сравнению с TimerTask?
Ответы
Ответ 1
Три возможности, о которых я могу думать:
- У вас огромное количество потоков, которые делают это, и они постоянно переключаются в контекст. Использование таймера будет означать только один поток. С другой стороны, это означает, что вы получите только одну задачу, выполняемую за раз.
- У вас есть оператор
continue;
где-то в вашем цикле перед сном, поэтому, даже если основная часть работы цикла не выполняется очень часто, что-то есть. Трудно сказать, не видя еще более конкретного кода.
- У вас сломанная комбинация JVM/OS. По-видимому, это кажется маловероятным.
Простой цикл, выполняющий только Thread.sleep(1000)
, должен быть очень дешевым - и вам также будет легко проверить его.
Ответ 2
Сравните скорость вашего процессора, поток и таймер. Timertask - более медленный поток (намного медленнее).