Czytałam o tym trochę w ciągu ostatnich kilku godzin, a ja po prostu nie widzę żadnego powodu ( ważny powód), aby wywołać shutdown()
na ExecutorService
, chyba że mamy humongous aplikację, która przechowuje, dziesiątki i dziesiątki różnych usług executorów, które nie są wykorzystywane do długo.
Jedyną rzeczą (z tego, co wiem) powoduje zamknięcie, jest zrobienie tego, co robi normalny wątek po zakończeniu. Kiedy normalny wątek zakończy metodę uruchamiania Runnable (lub Callable), zostanie przekazany do Garbage Collection w celu zebrania. Dzięki usłudze Executor wątki zostaną po prostu wstrzymane, nie będą zaznaczane do czyszczenia pamięci. W tym celu konieczne jest wyłączenie.
Ok, wracając do mojego pytania. Czy jest jakiś powód, aby wywoływać wyłączenie ExecutorService
bardzo często, a nawet zaraz po przesłaniu mu niektórych zadań? Chciałbym zostawić przypadek, gdy ktoś to robi i zaraz po tym dzwoni, awaitTermination()
ponieważ jest to sprawdzane. Kiedy już to zrobimy, musimy odtworzyć ExecutorService
wszystko od nowa, aby zrobić to samo. Czy to nie jest cały pomysł na ExecutorService
ponowne wykorzystanie wątków? Po co więc niszczyć ExecutorService
tak szybko?
Czy nie jest to racjonalny sposób, aby po prostu stworzyć ExecutorService
(lub połączyć w pary w zależności od tego, ile potrzebujesz), a następnie podczas działania aplikacji przekazać im zadania, gdy się pojawią, a następnie przy zamknięciu aplikacji lub innych ważnych etapach zamknąć te executory ?
Chciałbym uzyskać odpowiedź od niektórych doświadczonych programistów, którzy piszą dużo kodu asynchronicznego za pomocą ExecutorServices.
Drugie pytanie poboczne, trochę mniejsze oferty dotyczące platformy Android. JEŚLI niektórzy z was powiedzą, że nie jest najlepszym pomysłem zamykanie wykonawców za każdym razem, a programujecie na Androidzie, czy moglibyście mi powiedzieć, jak radzicie sobie z tymi zamknięciami (a konkretnie - kiedy je wykonujemy), gdy mamy do czynienia z różnymi zdarzeniami cykl życia aplikacji.
Ze względu na komentarz CommonsWare post został napisany jako neutralny. Naprawdę nie jestem zainteresowany kłótniami na śmierć i wydaje się, że to tam prowadzi. Interesuje mnie tylko dowiedzenie się, o co pytałem tutaj doświadczonych programistów, jeśli zechcą podzielić się swoimi doświadczeniami. Dzięki.
źródło
Odpowiedzi:
shutdown()
Metoda robi jedno: uniemożliwia klientom wysłać więcej pracy z usługą executora. Oznacza to, że wszystkie istniejące zadania będą nadal działać do ukończenia, chyba że zostaną podjęte inne działania. Dzieje się tak nawet w przypadku zaplanowanych zadań, np. ScheduledExecutorService: nowe wystąpienia zaplanowanego zadania nie będą uruchamiane. Może to być przydatne w różnych scenariuszach.Załóżmy, że masz aplikację konsolową, która ma usługę wykonawczą wykonującą N zadań. Jeśli użytkownik naciśnie CTRL-C, spodziewasz się, że aplikacja zakończy działanie, prawdopodobnie z wdziękiem. Co to znaczy wdzięcznie? Może chcesz, aby Twoja aplikacja nie była w stanie przesłać więcej zadań do usługi wykonawczej, a jednocześnie chcesz poczekać na zakończenie istniejących N zadań. Możesz to osiągnąć za pomocą haka zamykającego w ostateczności:
final ExecutorService service = ... // get it somewhere Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { System.out.println("Performing some shutdown cleanup..."); service.shutdown(); while (true) { try { System.out.println("Waiting for the service to terminate..."); if (service.awaitTermination(5, TimeUnit.SECONDS)) { break; } } catch (InterruptedException e) { } } System.out.println("Done cleaning"); } }));
Ten punkt zaczepienia wyłączy usługę, co uniemożliwi aplikacji przesyłanie nowych zadań i zaczeka na zakończenie wszystkich istniejących zadań przed zamknięciem maszyny JVM. Zakończenie oczekiwania zostanie zablokowane na 5 sekund i zwróci wartość true, jeśli usługa zostanie zamknięta. Odbywa się to w pętli, dzięki czemu masz pewność, że usługa zostanie ostatecznie zamknięta. Wyjątek InterruptedException zostaje za każdym razem połknięty. Jest to najlepszy sposób na zamknięcie usługi wykonawczej, która jest ponownie używana w całej aplikacji.
Ten kod nie jest doskonały. Jeśli nie jesteś absolutnie pewien, że Twoje zadania w końcu się zakończą, możesz poczekać na określony limit czasu, a następnie po prostu wyjść, porzucając uruchomione wątki. W takim przypadku sensowne byłoby również wywołanie
shutdownNow()
po przekroczeniu limitu czasu w ostatniej próbie przerwania uruchomionych wątków (shutdownNow()
poda również listę zadań oczekujących na uruchomienie). Jeśli twoje zadania są zaprojektowane tak, aby reagować na przerwy, to zadziała dobrze.Innym interesującym scenariuszem jest sytuacja, gdy masz usługę ScheduledExecutorService, która wykonuje zadania okresowe. Jedynym sposobem na zatrzymanie łańcucha zadań okresowych jest zadzwonienie
shutdown()
.EDYCJA: Chciałbym dodać, że nie polecałbym używania haka zamykającego, jak pokazano powyżej w ogólnym przypadku: może to być podatne na błędy i powinno być tylko ostatecznością. Ponadto, jeśli masz zarejestrowanych wiele punktów zaczepienia zamykających, kolejność ich uruchamiania jest niezdefiniowana, co może być niepożądane. Wolałbym mieć aplikację jawnie wywołać
shutdown()
naInterruptedException
.źródło
shutdown()
jej, aby nie marnować zasobów, gdy są niepotrzebne. Jeśli aplikacja zostanie zamknięta, wątki w puli zostaną ostatecznie usunięte z pamięci (domyślnie po 60 sekundach bezczynności). Zwróć uwagę, że jeśli chcesz, aby pula była ograniczona lub chcesz mieć inny czas życia wątku, możeszThreadPoolExecutor
bezpośrednio utworzyć plik .Tak. Nie powinieneś
ExecutorService
często niszczyć i odtwarzać . Zainicjuj,ExecutorService
gdy potrzebujesz (głównie podczas uruchamiania) i utrzymuj ją aktywną, dopóki nie skończysz.Tak. Racjonalne jest zamykanie
ExecutorService
ważnych etapów, takich jak zamykanie aplikacji itp.Załóżmy, że
ExecutorService
jest to współużytkowane przez różne działania w aplikacji. Każde działanie będzie wstrzymywane / wznawiane w różnych odstępach czasu, a nadal potrzebujesz jednegoExecutorService
dla swojej aplikacji.Zamiast zarządzać stanem
ExecutorService
metod cyklu życia działania, przenieś zarządzanie ExecutorService (tworzenie / zamykanie) do usługi niestandardowej .Utwórz
ExecutorService
w Service =>onCreate()
i zamknij go poprawnie wonDestroy()
Zalecany sposób wyłączania
ExecutorService
:Jak prawidłowo zamknąć java ExecutorService
źródło
Książka referencyjna
Opiekun: 14 Strona: 814
źródło
Powód wywołania shutdown () w ExecutorService
Dzisiaj spotkałem się z sytuacją, w której muszę poczekać, aż maszyna będzie gotowa, zanim rozpocznę serię zadań na tej maszynie.
Wykonuję wywołanie REST do tego komputera, jeśli nie otrzymam numeru 503 (serwer niedostępny), oznacza to, że maszyna jest gotowa do przetwarzania moich żądań. Tak więc czekam, aż otrzymam 200 (powodzenie) na pierwsze połączenie REST.
Istnieje wiele sposobów, aby to osiągnąć, użyłem ExecutorService do utworzenia wątku i zaplanowałem jego uruchamianie co X sekund. Więc muszę zatrzymać ten wątek pod warunkiem, sprawdź to ...
final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); Runnable task = () -> { try { int statusCode = restHelper.firstRESTCall(); if (statusCode == 200) { executor.shutdown(); } } catch (Exception e) { e.printStackTrace(); } }; int retryAfter = 60; executor.scheduleAtFixedRate(task, 0, retryAfter, TimeUnit.SECONDS);
Drugie pytanie poboczne, trochę mniejsze oferty dotyczące platformy Android.
Może mogę odpowiedzieć, jeśli podasz trochę więcej kontekstu! Z mojego doświadczenia w programowaniu na Androida wynika, że rzadko potrzebujesz wątków. Tworzysz grę lub aplikację, która wymaga wątków do działania? Jeśli nie, w Androidzie masz inne sposoby rozwiązania problemów, takich jak scenariusz, który wyjaśniłem powyżej. Możesz raczej użyć TimerTask, AsyncTask lub Handlers lub Loaders w oparciu o kontekst. Dzieje się tak, ponieważ jeśli UIThread czeka długo, wiesz, co się stanie: /
źródło
Dzieje się tak niezależnie od planowanych przedsięwzięć, np. Dla ScheduledExecutorService: nowe przypadki zarezerwowanego zlecenia nie będą uruchamiane.
Powinniśmy oczekiwać, że masz wygodną aplikację, która ma administratora agenta wykonującego N zadań.
Nie łapię tego bez wysiłku? Być może potrzebujesz, aby Twoja aplikacja nie miała możliwości przesłania większej liczby zleceń do administracji agentów, a tymczasem musisz być cierpliwy, aby Twoje obecne zadania N zostały zakończone.
Z wyjątkiem, jeśli jesteś całkowicie przekonany, że Twoje sprawunki w końcu się wyczerpią, powinieneś siedzieć mocno na daną przerwę, a następnie po prostu wyjść, opuszczając biegnące struny.
W przypadku, gdy Twoje działania mają na celu reagowanie na zakłócenia, będzie to działać dobrze.
Inną intrygującą sytuacją jest punkt, w którym masz usługę ScheduledExecutorService, która odtwarza działanie.
Najlepszym sposobem na zatrzymanie łańcucha działań jest wywołanie funkcji shutdown ()
źródło