Znalazłem tutaj podobne pytania, ale nie znalazłem odpowiedzi w sposób satysfakcjonujący. Więc ponownie sformułuj pytanie
Mam zadanie, które należy wykonywać okresowo (powiedzmy w odstępach 1-minutowych). Jaka jest zaleta korzystania z funkcji Timertask i Timer, w przeciwieństwie do tworzenia nowego wątku, który ma nieskończoną pętlę ze snem?
Fragment kodu za pomocą timertask-
TimerTask uploadCheckerTimerTask = new TimerTask(){
public void run() {
NewUploadServer.getInstance().checkAndUploadFiles();
}
};
Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(uploadCheckerTimerTask, 0, 60 * 1000);
Fragment kodu używający wątku i uśpienia
Thread t = new Thread(){
public void run() {
while(true) {
NewUploadServer.getInstance().checkAndUploadFiles();
Thread.sleep(60 * 1000);
}
}
};
t.start();
Naprawdę nie muszę się martwić, jeśli przegapię pewne cykle, jeśli wykonanie logiki zajmuje więcej niż czas interwału.
Proszę o komentarz na ten temat ...
Aktualizacja:
Ostatnio znalazłem kolejną różnicę między używaniem Timera a Thread.sleep (). Załóżmy, że aktualny czas systemowy to 11:00. Jeśli z jakiegoś powodu cofniemy czas systemowy do godziny 10:00, Timer ZATRZYMUJE wykonywanie zadania do godziny 11:00, podczas gdy metoda Thread.sleep () będzie kontynuować wykonywanie zadania bez przeszkód. Może to być główny decydent przy podejmowaniu decyzji, co użyć między tymi dwoma.
Odpowiedzi:
Zaletą TimerTask jest to, że znacznie lepiej wyraża on Twój zamiar (tj. Czytelność kodu) i ma już zaimplementowaną funkcję cancel ().
Zwróć uwagę, że można go napisać w krótszej formie, jak również własny przykład:
źródło
Timer / TimerTask bierze również pod uwagę czas wykonania twojego zadania, więc będzie trochę dokładniejszy. I lepiej radzi sobie z problemami wielowątkowymi (takimi jak unikanie zakleszczeń itp.). I oczywiście zwykle lepiej jest użyć dobrze przetestowanego standardowego kodu zamiast jakiegoś domowego rozwiązania.
źródło
Nie wiem dlaczego, ale program, który pisałem, używał timerów, a jego rozmiar sterty stale się zwiększał, gdy zmieniłem go na rozwiązany problem wątku / snu.
źródło
Jeśli wątek dostanie wyjątek i zostanie zabity, to jest problem. Ale TimerTask zajmie się tym. Będzie działać niezależnie od awarii w poprzednim przebiegu.
źródło
Z
Timer
dokumentacji :Więc wolę
ScheduledThreadExecutor
zamiastTimer
:Timer
używa pojedynczego wątku w tle, który jest używany do sekwencyjnego wykonywania wszystkich zadań timera. Zadania powinny więc zakończyć się szybko, w przeciwnym razie opóźni to wykonanie kolejnych zadań. Ale w tym przypadkuScheduledThreadPoolExecutor
możemy skonfigurować dowolną liczbę wątków, a także mieć pełną kontrolę, udostępniającThreadFactory
.Timer
może być wrażliwy na zegar systemowy, ponieważ korzysta zObject.wait(long)
metody. AleScheduledThreadPoolExecutor
tak nie jest.ScheduledThreadPoolExecutor
aby nie wpływać na inne zadania.Timer
zapewniacancel
metodę kończenia licznika czasu i odrzucania zaplanowanych zadań, jednak nie koliduje z aktualnie wykonywanym zadaniem i nie pozwala na jego zakończenie. Ale jeśli zegar działa jako wątek demona, to niezależnie od tego, czy go anulujemy, czy nie, zakończy się, gdy tylko wszystkie wątki użytkownika zostaną zakończone.Timer vs Thread.sleep
Timer korzysta z
Object.wait
i różni się odThread.sleep
wait
) wątek może zostać powiadomiony (za pomocąnotify
) przez inny wątek, ale śpiącego nie można, można go tylko przerwać.źródło
Jest jeden kluczowy argument przeciwko zarządzaniu tym zadaniem za pomocą wątków i
sleep
metody Java . Używaszwhile(true)
do pozostawania w pętli na czas nieokreślony i hibernacji wątku poprzez uśpienie. A jeśliNewUploadServer.getInstance().checkAndUploadFiles();
zajmie trochę zsynchronizowanych zasobów. Inne wątki nie będą miały dostępu do tych zasobów, może zdarzyć się głód, który może spowolnić całą aplikację. Tego typu błędy są trudne do zdiagnozowania i dobrze jest zapobiegać ich występowaniu.Drugie podejście wyzwala wykonanie kodu, który jest dla Ciebie ważny, tj. Poprzez
NewUploadServer.getInstance().checkAndUploadFiles();
wywołanie swojejrun()
metodyTimerTask
, pozwalając w międzyczasie innym wątkom korzystać z zasobów.źródło
Myślę, że rozumiem Twój problem, widzę coś bardzo podobnego. Mam cykliczne liczniki czasu, niektóre co 30 minut, a niektóre co kilka dni. Z tego, co przeczytałem i z komentarzy, które widzę, wygląda na to, że zbieranie śmieci nigdy nie zostanie uruchomione, ponieważ wszystkie zadania nigdy nie są zakończone. Pomyślałbym, że zbieranie śmieci będzie działać, gdy zegar jest w stanie uśpienia, ale ja go nie widzę i zgodnie z dokumentacją nie.
Myślę, że tworzenie nowych wątków kończy się i pozwala na zbieranie śmieci.
Niech ktoś udowodni, że się mylę, przepisywanie tego, co odziedziczyłem, będzie bolało.
źródło