Timer & TimerTask порівняно з Thread + сон на Java


102

Тут я знайшов подібні запитання, але на моє задоволення відповіді не було. Тож перефразовуючи це питання знову -

У мене є завдання, яке потрібно виконувати періодично (скажімо, 1-хвилинний інтервал). Яка перевага використання Timertask & Timer для цього, а не створення нової нитки, яка має нескінченний цикл зі сном?

Фрагмент коду за допомогою таймертаска-

TimerTask uploadCheckerTimerTask = new TimerTask(){

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

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

Фрагмент коду за допомогою теми "

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

Мені дійсно не потрібно хвилюватися, якщо я пропускаю певні цикли, якщо виконання логіки займає більше інтервалу часу.

Будь ласка, прокоментуйте це ..

Оновлення:
Нещодавно я виявив ще одну різницю між використанням таймера та Thread.sleep (). Припустимо, поточний системний час - 11:00. Якщо ми відкинемо системний час до 10:00 з якоїсь причини, Таймер зупинить виконання завдання, поки не досягне 11:00 ранку, тоді як метод Thread.sleep () буде продовжувати виконувати завдання без перешкод. Це може бути головним органом, що приймає рішення, вирішити, що використовувати між цими двома.


21
Порядок порядку: Таймер і TimerTask застаріли і фактично були замінені ExecutorService, хоча ваша точка все ще стоїть.
skaffman

Дякую за пораду, я вирішив скористатися ExecutorService :)
Keshav

Дякую всім за відповіді, безумовно, дав мені більше розуміння!
Кешав

6
Таймер не застарілий, і його віддають перевагу, коли потрібна лише одна нитка. ( java.sun.com/javase/6/docs/api/java/util/Timer.html )
Джастін

2
Таймер і TimerTask все ще корисні в середовищах JME, де ExecutorService не існує (оскільки заснована на JME Java 1.3 ...).
ス ー パ ー フ ァ ミ ン

Відповіді:


67

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

Зауважте, що це може бути написано у коротшій формі, а також власний приклад:

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(
    new TimerTask() {
      public void run() { NewUploadServer.getInstance().checkAndUploadFiles(); }
    }, 0, 60 * 1000);

якщо таймер використовується для Щоденного, 2 конкретного часу 9 вечора та 9 ранку, ... як дати значення? на код вище ... @ Zed?
gumuruh

12

Timer / TimerTask також враховує час виконання вашого завдання, тому це буде трохи точніше. І він краще займається питаннями багатопотокової роботи (наприклад, уникнення тупикових ситуацій тощо). І звичайно, зазвичай краще використовувати добре перевірений стандартний код замість якогось домашнього рішення.


5

Я не знаю, чому, але програма, яку я писав, використовувала таймери, і розмір купи її постійно збільшувався, як тільки я змінив її на проблему "Нитка / сон".


9
Таймер створює чергу завдань, яка постійно оновлюється. Коли Таймер готовий, сміття може бути зібране не відразу. Таким чином, створення більшої кількості таймерів лише додає більше об'єктів у купу. Thread.sleep () лише призупиняє потік, тому накладні витрати на пам'ять були б надзвичайно низькими.
Дарріл Джерроу

4

Якщо ви нитка отримуєте виняток і вас вбивають, це проблема. Але TimerTask подбає про це. Він буде працювати незалежно від відмови в попередньому циклі.


4

З Timer документації :

Java 5.0 представила пакет java.util.concurrent і однією з утиліт одночасності в ньому є ScheduledThreadPoolExecutor, що є пулом потоків для багаторазового виконання завдань із заданою швидкістю або затримкою. Це фактично більш універсальна заміна комбінації Timer / TimerTask, оскільки вона дозволяє безліч службових потоків, приймає різні одиниці часу і не вимагає підкласингу TimerTask (просто реалізуйте Runnable). Налаштування ScheduledThreadPoolExecutor з одним потоком робить його еквівалентним Таймеру.

Тому віддайте перевагу ScheduledThreadExecutorзамість Timer:

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

Таймер проти теми

Таймер використовує Object.waitі він відрізняється відThread.sleep

  1. waitНитка, що чекає, може бути сповіщена (використовуючи notify) іншою ниткою, але сплячої не може бути, її можна лише перервати.
  2. Очікування (і повідомлення) повинно відбуватися в блоці, синхронізованому на об'єкті монітора, тоді як сон не відбувається.
  3. Поки сплячий не відпускає замок, очікування відпустить замок для очікування очікування об'єкта.

дуже корисна інформація, Плюс використання Thread.sleep у нескінченному циклі може призвести до високого використання процесора за малих затримок часу.
Амір Фо

3

Існує один вирішальний аргумент проти управління цим завданням за допомогою потоків і sleepметодів Java . Ви використовуєте while(true)нескінченно триматися в циклі і перезимувати нитку, укладаючи спати. Що робити, якщо NewUploadServer.getInstance().checkAndUploadFiles();зайняті деякі синхронізовані ресурси. Інші теми не зможуть отримати доступ до цих ресурсів, може виникнути голодування, яке може сповільнити вашу програму. Такі помилки важко діагностувати, і це гарна ідея запобігти їх існуванню.

Інший підхід запускає виконання важливого для вас коду, тобто NewUploadServer.getInstance().checkAndUploadFiles();, викликаючи run()метод вашого, TimerTaskпоки тим часом дозволяючи іншим потокам використовувати ресурси.


16
Я не розумію цього аргументу. Обидва варіанти запускають один і той же метод з потоку, обидва варіанти сплять у нитці, поки вони чекають виконання. Не буде різниць голоду між двома варіантами.
satur9nine

2

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

Я думаю, що нерест нових ниток завершує і дозволяє збирати сміття.

Хтось, будь ласка, доведіть мене неправильно, переписування того, що я успадкував, буде болем.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.