Timer Java vs ExecutorService?

263

Mam kod, za pomocą którego planuję zadanie java.util.Timer. Rozejrzałem się i zobaczyłem, że ExecutorServicemogę zrobić to samo. To pytanie tutaj, czy używałeś Timeri ExecutorServiceplanowałeś zadania, jaka jest korzyść z jednego korzystania z drugiego?

Chciałem również sprawdzić, czy ktoś skorzystał z Timerklasy i napotkał problemy, które ExecutorServicedla nich rozwiązały.

kal
źródło
1
A jeśli potrzebujesz czegoś jeszcze bardziej funkcjonalnego, sprawdź kwarc . Daje to znacznie większą kontrolę nad zadaniami, w tym planowanie takie jak cron, planowanie uwzględniające klastry, zindywidualizowana kontrola nad zadaniami (pojęcia takie jak uruchamianie na raz, zależności itp.).
Tim

Odpowiedzi:

313

Według Java Concurrency in Practice :

  • Timermoże być wrażliwy na zmiany w zegarze systemowym, ScheduledThreadPoolExecutorprawda.
  • Timerma tylko jeden wątek wykonania, więc długotrwałe zadanie może opóźnić inne zadania. ScheduledThreadPoolExecutormożna skonfigurować z dowolną liczbą wątków. Ponadto masz pełną kontrolę nad tworzonymi wątkami, jeśli chcesz (pod warunkiem ThreadFactory).
  • Zgłoszone wyjątki środowiska wykonawczego TimerTaskzabijają ten jeden wątek, powodując w ten sposób Timerutratę :-( ... tj. Zaplanowane zadania nie będą już działać. ScheduledThreadExecutorNie tylko wychwytują wyjątki środowiska wykonawczego, ale także pozwalają je obsłużyć, jeśli chcesz (zastępując afterExecutemetodę z ThreadPoolExecutor). Zadanie, które zgłoszony wyjątek zostanie anulowany, ale inne zadania będą nadal działać.

Jeśli możesz użyć ScheduledThreadExecutorzamiast Timer, zrób to.

Jeszcze jedna rzecz ... chociaż ScheduledThreadExecutornie jest dostępna w bibliotece Java 1.4, istnieje Backport JSR 166 ( java.util.concurrent) do Java 1.2, 1.3, 1.4 , który ma ScheduledThreadExecutorklasę.

Peter Štibraný
źródło
63

Jeśli jest on dostępny, trudno jest wymyślić powód, aby nie używać frameworka Java 5. Powołanie:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

da ci ScheduledExecutorServicepodobną funkcjonalność do Timer(tj. będzie jednowątkowy), ale do którego dostęp może być nieco bardziej skalowalny (pod maską używa współbieżnych struktur zamiast pełnej synchronizacji jak w przypadku Timerklasy). Użycie a ScheduledExecutorServicedaje również takie korzyści, jak:

  • W razie potrzeby możesz go dostosować (patrz klasa newScheduledThreadPoolExecutor()lub ScheduledThreadPoolExecutor)
  • Wykonania jednorazowe mogą zwracać wyniki

Jedyne powody, dla Timerktórych mogę się trzymać , to:

  • Jest dostępny przed Java 5
  • Podobna klasa znajduje się w J2ME, co może ułatwić przenoszenie aplikacji (ale w tym przypadku nie byłoby strasznie trudno dodać wspólną warstwę abstrakcji)
Neil Coffey
źródło
1
Innym powodem użycia TimerTaskmoże być dostępność scheduledExecutionTime()metody, która nie wydaje się mieć odpowiednika w ScheduledExecutorService.
Rohit Agarwal
3
Kolejna uwaga: piszę ten komentarz w 2k17, nie ma już J2ME. już jest martwy.
msangel
1
Klasa Java Timer jest kiepska.
JohnyTex,
26

ExecutorService jest nowszy i bardziej ogólny. Timer to tylko wątek, który okresowo uruchamia zaplanowane dla niego rzeczy.

Usługa ExecutorService może być pulą wątków lub nawet rozproszona na inne systemy w klastrze i wykonywać takie czynności, jak jednorazowe wykonywanie wsadowe itp.

Wystarczy spojrzeć na to, co każda oferta decyduje.

Dustin
źródło
16

Oto kilka dobrych praktyk dotyczących korzystania z timera:

http://tech.puredanger.com/2008/09/22/timer-rules/

Ogólnie rzecz biorąc, używałbym Timera do szybkich i brudnych rzeczy, a Executora do bardziej niezawodnego użytkowania.

Alex Miller
źródło
8

Ze strony dokumentacji Oracle na ScheduledThreadPoolExecutor

ThreadPoolExecutor które mogą dodatkowo zaplanować polecenia uruchomienia po określonym opóźnieniu, lub okresowo wykonania. Ta klasa jest lepsza niż Timer, gdy potrzebnych jest wiele wątków roboczych lub gdy wymagana jest dodatkowa elastyczność lub możliwości ThreadPoolExecutor (który rozszerza tę klasę).

ExecutorService/ThreadPoolExecutorlub ScheduledThreadPoolExecutorjest oczywistym wyborem, jeśli masz wiele wątków roboczych.

Zalety ExecutorServiceponadTimer

  1. Timernie może korzystać z dostępnych rdzeni procesora, w przeciwieństwie ExecutorServicedo wielu zadań z wykorzystaniem smaków ExecutorServicetakich jak ForkJoinPool
  2. ExecutorServicezapewnia wspólny interfejs API, jeśli potrzebujesz koordynacji między wieloma zadaniami. Załóżmy, że musisz przesłać N liczby zadań roboczych i poczekać na ich zakończenie. Możesz to łatwo osiągnąć dzięki invokeAll API. Jeśli chcesz osiągnąć to samo z wieloma Timerzadaniami, nie byłoby to proste.
  3. ThreadPoolExecutor zapewnia lepszy interfejs API do zarządzania cyklem życia wątku.

    Pule wątków rozwiązują dwa różne problemy: zazwyczaj zapewniają lepszą wydajność podczas wykonywania dużej liczby zadań asynchronicznych, ze względu na zmniejszone obciążenie wywołania poszczególnych zadań, oraz zapewniają ograniczenie i zarządzanie zasobami, w tym wątkami, zużywanymi podczas wykonywania kolekcji zadania Każdy ThreadPoolExecutor prowadzi także podstawowe statystyki, takie jak liczba zakończonych zadań

    Kilka zalet:

    za. Możesz tworzyć / zarządzać / kontrolować cykl życia wątków i optymalizować koszty tworzenia wątków

    b. Możesz kontrolować przetwarzanie zadań (kradzież pracy, ForkJoinPool, invokeAll) itp.

    do. Możesz monitorować postęp i zdrowie wątków

    re. Zapewnia lepszy mechanizm obsługi wyjątków

Ravindra babu
źródło
5

Moim powodem, dla którego czasami wolę Timer niż Executors.newSingleThreadScheduledExecutor (), jest to, że otrzymuję znacznie czystszy kod, gdy potrzebuję timera do wykonania na wątkach demona.

porównać

private final ThreadFactory threadFactory = new ThreadFactory() {
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
};
private final ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor(threadFactory); 

z

private final Timer timer = new Timer(true);

Robię to, gdy nie potrzebuję solidności usługi wykonawczej.

Siamaster
źródło