Timer & TimerTask против Thread + sleep в Java - PullRequest
101 голосов
/ 21 сентября 2009

Я нашел похожие вопросы, задаваемые здесь, но не было ответов на мое удовлетворение. Так что перефразируя вопрос снова -

У меня есть задача, которую нужно выполнять периодически (скажем, с интервалом в 1 минуту). В чем преимущество использования Timertask & Timer по сравнению с созданием нового потока, имеющего бесконечный цикл со сном?

Фрагмент кода с использованием timertask-

TimerTask uploadCheckerTimerTask = new TimerTask(){

 public void run() {
  NewUploadServer.getInstance().checkAndUploadFiles();
 }
};

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(uploadCheckerTimerTask, 0, 60 * 1000);

Фрагмент кода с использованием Thread и sleep-

Thread t = new Thread(){
 public void run() {
  while(true) {
   NewUploadServer.getInstance().checkAndUploadFiles();
   Thread.sleep(60 * 1000);
  }
 }
};
t.start();

Мне действительно не нужно беспокоиться, если я пропущу определенные циклы, если выполнение логики занимает больше времени интервала.

Прокомментируйте, пожалуйста, это ..

Обновление:
Недавно я обнаружил еще одну разницу между использованием Timer и Thread.sleep (). Предположим, что текущее системное время 11:00. Если по какой-то причине мы откатим системное время до 10:00, Timer остановит выполнение задачи, пока она не достигнет 11:00, тогда как метод Thread.sleep () продолжит выполнение задачи без помех. Это может быть важным фактором при принятии решения о том, что использовать между этими двумя.

Ответы [ 7 ]

66 голосов
/ 21 сентября 2009

Преимущество TimerTask заключается в том, что он гораздо лучше выражает ваши намерения (то есть читабельность кода), и в нем уже реализована функция cancel ().

Обратите внимание, что его можно записать в более короткой форме, а также на собственном примере:

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(
    new TimerTask() {
      public void run() { NewUploadServer.getInstance().checkAndUploadFiles(); }
    }, 0, 60 * 1000);
13 голосов
/ 21 сентября 2009

Timer / TimerTask также учитывает время выполнения вашей задачи, поэтому оно будет немного более точным. И он лучше справляется с проблемами многопоточности (например, избегая взаимоблокировок и т. Д.). И, конечно, обычно лучше использовать хорошо проверенный стандартный код, а не какое-то домашнее решение.

5 голосов
/ 03 октября 2011

Я не знаю, почему, но программа, которую я писал, использовала таймеры, и размер кучи постоянно увеличивался, как только я сменил ее на Thread / sleep, проблема решена.

4 голосов
/ 06 февраля 2014

Если ваш поток получает исключение и его убивают, это проблема. Но TimerTask позаботится об этом. Он будет работать независимо от сбоя в предыдущем запуске.

3 голосов
/ 13 сентября 2018

Из документации Timer :

Java 5.0 представила пакет java.util.concurrent и один из утилиты параллелизма в нем - ScheduledThreadPoolExecutor, который пул потоков для многократного выполнения задач с заданной скоростью или задержка. Это фактически более универсальная замена для Комбинация Timer / TimerTask, так как она позволяет использовать несколько потоков услуг, принимает различные единицы времени и не требует создания подклассов TimerTask (просто реализовать Runnable). Настройка ScheduledThreadPoolExecutor с одним потоком делает его эквивалентным Таймеру.

Так что предпочитайте ScheduledThreadExecutor вместо Timer:

  • Timer использует один фоновый поток, который используется для последовательного выполнения всех задач таймера. Таким образом, задачи должны выполняться быстро, иначе это задержит выполнение последующих задач. Но в случае ScheduledThreadPoolExecutor мы можем настроить любое количество потоков, а также иметь полный контроль, предоставив ThreadFactory.
  • Timer может быть чувствительным к системным часам, так как использует метод Object.wait(long). Но ScheduledThreadPoolExecutor это не так.
  • Исключения во время выполнения, выдаваемые в TimerTask, убивают этот конкретный поток, тем самым останавливая Timer, где мы можем справиться с этим в ScheduledThreadPoolExecutor, чтобы другие задачи не затрагивались.
  • Timer предоставляет cancel метод для завершения таймера и сброса любых запланированных задач, однако он не мешает выполнению текущей задачи и не позволяет ей завершиться. Но если таймер работает как поток демона, то независимо от того, отменили мы его или нет, он прекратит работу, как только все пользовательские потоки закончат выполнение.

Таймер против Thread.sleep

Таймер использует Object.wait и отличается от Thread.sleep

  1. Ожидающий (wait) поток может быть уведомлен (используя notify) другим потоком, но не может быть спящим, его можно только прервать.
  2. Ожидание (и уведомление) должно происходить в блоке, синхронизированном на объекте монитора, тогда как спящий режим не происходит.
  3. Пока сон не снимает блокировку, ожидание снимает блокировку для вызова объекта, ожидающего ожидания.
3 голосов
/ 21 сентября 2009

Есть один важный аргумент против управления этой задачей с использованием потоков Java и метода sleep. Вы используете while(true), чтобы оставаться в цикле неограниченное время и переводить нить в спящий режим, переводя его в спящий режим. Что делать, если NewUploadServer.getInstance().checkAndUploadFiles(); занимает некоторые синхронизированные ресурсы. Другие потоки не смогут получить доступ к этим ресурсам, может произойти голодание, которое может замедлить работу всего приложения. Подобные ошибки трудно диагностировать, и рекомендуется предотвращать их появление.

Другой подход запускает выполнение кода, который важен для вас, то есть NewUploadServer.getInstance().checkAndUploadFiles();, вызывая метод run() вашего TimerTask, в то же время позволяя другим потокам использовать ресурсы тем временем.

1 голос
/ 20 ноября 2014

Мне кажется, я понимаю вашу проблему, я вижу нечто очень похожее. У меня есть таймеры, которые повторяются, некоторые каждые 30 минут, а некоторые каждые пару дней. Из того, что я прочитал, и из комментариев, которые я вижу, похоже, что сборка мусора никогда не запустится, потому что все задачи никогда не завершаются. Я бы подумал, что сборка мусора будет запускаться, когда таймер находится в спящем режиме, но я его не вижу и, согласно документации, этого не происходит.

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

Кто-то, пожалуйста, докажите, что я не прав, переписать то, что я унаследовал, будет боль.

...