Grund für den Aufruf von shutdown () in ExecutorService

84

Ich habe in den letzten paar Stunden ziemlich viel darüber gelesen, und ich kann einfach keinen Grund ( gültigen Grund) erkennen, shutdown()auf den ExecutorServicezuzugreifen, es sei denn, wir haben eine riesige Anwendung, die Dutzende und Dutzende verschiedener Executor-Dienste speichert, für die sie nicht verwendet werden eine lange Zeit.

Das einzige, was das Herunterfahren bewirkt (soweit ich weiß), ist das, was ein normaler Thread tut, sobald es fertig ist. Wenn der normale Thread die Ausführungsmethode von Runnable (oder Callable) beendet, wird sie zur Erfassung an Garbage Collection übergeben. Mit Executor Service werden die Threads einfach angehalten und nicht für die Garbage Collection angekreuzt. Dafür wird das Herunterfahren benötigt.

Ok zurück zu meiner Frage. Gibt es einen Grund, Shutdown ExecutorServicesehr oft oder sogar direkt nach dem Absenden einiger Aufgaben aufzurufen ? Ich möchte den Fall hinter mir lassen, dass jemand es tut und gleich danach anruft, awaitTermination()da dies bestätigt wird. Sobald wir das tun, müssen wir noch einmal ein neues erstellen ExecutorService, um dasselbe zu tun. Ist das nicht die ganze Idee für die ExecutorService, die Threads wiederzuverwenden? Warum also das ExecutorServiceso schnell zerstören ?

Ist es nicht eine rationale Methode, einfach zu erstellen ExecutorService(oder zu koppeln, je nachdem, wie viele Sie benötigen), dann während der Ausführung der Anwendung die Aufgaben an sie weiterzugeben, sobald sie ausgeführt werden, und dann beim Beenden der Anwendung oder in einigen anderen wichtigen Phasen diese Ausführenden herunterzufahren ?

Ich möchte eine Antwort von einigen erfahrenen Programmierern erhalten, die mit ExecutorServices viel asynchronen Code schreiben.

Zweite Nebenfrage, etwas kleiner befasst sich mit Android-Plattform. WENN einige von Ihnen sagen, dass es nicht die beste Idee ist, Executoren jedes Mal herunterzufahren und auf Android zu programmieren, können Sie mir sagen, wie Sie mit diesen Shutdowns umgehen (um genau zu sein - wenn Sie sie ausführen), wenn wir mit verschiedenen Ereignissen von Anwendungslebenszyklus.

Aufgrund des CommonsWare-Kommentars habe ich den Beitrag neutral gemacht. Ich bin wirklich nicht daran interessiert, darüber zu Tode zu streiten, und es scheint, dass es dorthin führt. Ich bin nur daran interessiert zu erfahren, was ich hier von erfahrenen Entwicklern gefragt habe, wenn sie bereit sind, ihre Erfahrungen zu teilen. Vielen Dank.

Lucas
quelle
3
"Ich sehe oft Beispielcodes, in denen die ganze Zeit direkt nach dem Einreichen oder Ausführen von Aufgaben ein Aufruf von shutdown () erfolgt". Sie können auch Hyperlinks verwenden, um Ihre Behauptungen nachzuweisen. Persönlich habe ich noch nie "Beispielcodes" gesehen, die das tun, was Sie angeben. Es ist möglich, dass Sie etwas falsch interpretieren, und wir können Sie nur darauf hinweisen, wenn wir wissen, welche "Beispielcodes" Sie untersuchen.
CommonsWare
4
Hallo CommonsWare. Zuallererst sehe ich einen aggressiven Ton von Ihnen (oder so scheint es) gegenüber mir, der meiner Meinung nach hier nicht bestätigt wird. Ich habe nicht versucht, Menschen negativ darzustellen. In Bezug auf Ihr Zitat habe ich hauptsächlich über den Teil "Thinking In Java IV Edition, Multitasking" gesprochen. In Bruce Eckels Beispielen finden Sie viele Beispiele dafür. Sie sind meistens einfach, aber trotzdem hatte Bruce den Eindruck, dass er sehr oft heruntergefahren wurde. In irgendeiner Weise haben Sie sich auf etwas konzentriert, das nicht der Hauptteil meines Beitrags war. Ich habe diese Teile entfernt, weil ich wirklich nicht darüber streiten möchte.
Lucas
1
hay @CommonsWare in Thinking in Java-Buch von Bruce Eckel..in Concurrency / Executor Seite 804 Vierte Ausgabe verwendet er immer die shutdown () -Methode direkt nach dem Senden oder Ausführen von Aufgaben in einfachen Apps, um zu veranschaulichen, wie Executor funktioniert, wie Lucas sagte
Fehler
2
Ich weiß, dass dies ein alter Beitrag ist, aber ich denke, die Frage des OP bleibt bestehen und ist gültig. Ich bin auch auf viele Beispielcodes gestoßen, bei denen "direkt nach execute () ein shutdown () -Aufruf erfolgt". tutorials.jenkov.com/java-util-concurrent/executorservice.html (erstes Tutorial, das
angezeigt wird
Vielen Dank, ich hatte die gleiche Frage, die mit diesen "Beispielcodes" aufgeworfen wurde. journaldev.com/2340/…
Gregordy

Antworten:

57

Die shutdown()Methode bewirkt eines: Verhindert, dass Clients mehr Arbeit an den Executor-Service senden. Dies bedeutet, dass alle vorhandenen Aufgaben weiterhin vollständig ausgeführt werden, sofern keine anderen Maßnahmen ergriffen werden. Dies gilt auch für geplante Aufgaben, z. B. für einen ScheduledExecutorService: Neue Instanzen der geplanten Aufgabe werden nicht ausgeführt. Dies kann in verschiedenen Szenarien hilfreich sein.

Angenommen, Sie haben eine Konsolenanwendung, auf der ein Executor-Dienst N Aufgaben ausführt. Wenn der Benutzer STRG-C drückt, wird die Anwendung möglicherweise ordnungsgemäß beendet. Was bedeutet es anmutig? Möglicherweise möchten Sie, dass Ihre Anwendung nicht mehr Aufgaben an den Executor-Service senden kann, und gleichzeitig möchten Sie warten, bis Ihre vorhandenen N Aufgaben abgeschlossen sind. Sie können dies als letzten Ausweg mit einem Abschalthaken erreichen:

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");
    }
}));

Dieser Hook beendet den Dienst, wodurch verhindert wird, dass Ihre Anwendung neue Aufgaben sendet, und wartet, bis alle vorhandenen Aufgaben abgeschlossen sind, bevor die JVM heruntergefahren wird. Die Wartezeit wird für 5 Sekunden blockiert und gibt true zurück, wenn der Dienst heruntergefahren wird. Dies erfolgt in einer Schleife, damit Sie sicher sind, dass der Dienst irgendwann heruntergefahren wird. Die InterruptedException wird jedes Mal verschluckt. Dies ist der beste Weg, um einen Executor-Dienst herunterzufahren, der in Ihrer gesamten Anwendung wiederverwendet wird.

Dieser Code ist nicht perfekt. Wenn Sie nicht absolut sicher sind, dass Ihre Aufgaben irgendwann beendet werden, möchten Sie möglicherweise auf eine bestimmte Zeitüberschreitung warten und dann einfach beenden und die laufenden Threads verlassen. In diesem Fall ist es sinnvoll, auch shutdownNow()nach dem Timeout aufzurufen, um die laufenden Threads zu unterbrechen ( shutdownNow()Sie erhalten auch eine Liste der Aufgaben, die auf die Ausführung warten). Wenn Ihre Aufgaben auf Unterbrechungen reagieren sollen, funktioniert dies einwandfrei.

Ein weiteres interessantes Szenario ist, wenn Sie einen ScheduledExecutorService haben, der eine periodische Aufgabe ausführt. Die einzige Möglichkeit, die Kette periodischer Aufgaben zu stoppen, ist ein Anruf shutdown().

EDIT: Ich möchte hinzufügen, dass ich nicht empfehlen würde, einen Shutdown-Hook zu verwenden, wie oben im allgemeinen Fall gezeigt: Er kann fehleranfällig sein und sollte nur ein letzter Ausweg sein. Wenn Sie viele Shutdown-Hooks registriert haben, ist die Reihenfolge, in der sie ausgeführt werden, undefiniert, was möglicherweise unerwünscht ist. Ich würde eher die Anwendung explizit rufen shutdown()auf InterruptedException.

Giovanni Botta
quelle
Sorry Giovanni für die späte Antwort und danke übrigens dafür. Ja, ich weiß, wie Executor funktioniert, was ich in meiner Frage zu erklären versucht habe. Das Herunterfahren macht das, was Sie gesagt haben, und ermöglicht es dem Garbage Collector, diese toten Threads zu sammeln und tatsächlich die ExecutorService-Instanz zu sammeln. Meine Frage war spezifisch. Gibt es einen Grund, die ganze Zeit "shutdown ()" aufzurufen, direkt nachdem Sie etwas auf ExecutorService gesendet / ausgeführt haben? Der zweite Teil der Frage bezieht sich ausschließlich auf die Android-Architektur. Wenn die Antwort auf die vorherige Antwort Nein lautet, müssen Sie während und während des Vorgangs das Herunterfahren aufrufen. Lebenszyklus.
Lucas
3
Es gibt keinen Grund, shutdown () ständig aufzurufen. Tatsächlich ist dies möglicherweise die absolut falsche Vorgehensweise, da Sie dadurch den Executor-Service nicht mehr wiederverwenden können. Der Grund, es am Ende des Lebenszyklus des Dienstes aufzurufen, besteht darin, dass die Threads schließlich, wie Sie bemerkt haben, durch Müll gesammelt werden können. Wenn Sie dies nicht tun, halten diese Threads die JVM am Leben, obwohl sie inaktiv sind.
Giovanni Botta
"Es gibt keinen Grund, shutdown () ständig aufzurufen. Tatsächlich ist dies möglicherweise die absolut falsche Vorgehensweise, da Sie dadurch den Executor-Service nicht erneut verwenden können." Das ist genau meine Argumentation und mein Dillema aus der ursprünglichen Frage. Um es noch einmal zu wiederholen, lautet die Frage: Wann sollte ich meinen ExecutiveService im Android-Lebenszyklus herunterfahren?
Lucas
2
Ich habe keine Android-Erfahrung, aber ich denke, Sie sollten es herunterfahren, wenn Ihre Anwendung heruntergefahren wird, damit die JVM endgültig beendet werden kann.
Giovanni Botta
3
Aha. Ich schlage vor, Sie verwenden einen zwischengespeicherten Thread-Pool und rufen shutdown()ihn niemals auf, damit Sie keine Ressourcen verschwenden, wenn dies nicht erforderlich ist. Wenn die Anwendung heruntergefahren wird, werden die Threads im Pool möglicherweise durch Müll gesammelt (nachdem sie standardmäßig 60 Sekunden lang inaktiv waren). Beachten Sie, dass Sie ThreadPoolExecutordirekt einen Pool erstellen können, wenn Sie möchten, dass der Pool begrenzt wird oder eine andere Thread-Lebensdauer haben soll .
Giovanni Botta
13

Ist es nicht die ganze Idee für den ExecutorService, die Threads wiederzuverwenden? Warum also den ExecutorService so schnell zerstören?

Ja. Sie sollten nicht häufig zerstören und neu erstellen ExecutorService. Initialisieren ExecutorServiceSie bei Bedarf (meistens beim Start) und lassen Sie es aktiv, bis Sie damit fertig sind.

Ist es nicht eine rationale Möglichkeit, ExecutorService einfach zu erstellen (oder zu koppeln, je nachdem, wie viele Sie benötigen), und dann während der Ausführung der Anwendung die Aufgaben an sie weiterzuleiten, sobald sie ausgeführt werden, und diese dann beim Beenden der Anwendung oder in einigen anderen wichtigen Phasen herunterzufahren Testamentsvollstrecker?

Ja. Es ist sinnvoll, ExecutorServicewichtige Phasen wie das Beenden von Anwendungen usw. herunterzufahren .

Zweite Nebenfrage, etwas kleiner befasst sich mit Android-Plattform. WENN einige von Ihnen sagen, dass es nicht die beste Idee ist, Executoren jedes Mal herunterzufahren und auf Android zu programmieren, können Sie mir sagen, wie Sie mit diesen Shutdowns umgehen (um genau zu sein, wenn Sie sie ausführen), wenn wir mit verschiedenen Anwendungsereignissen umgehen Lebenszyklus.

Angenommen, dies ExecutorServicewird für verschiedene Aktivitäten in Ihrer Anwendung freigegeben. Jede Aktivität wird in unterschiedlichen Zeitintervallen angehalten / fortgesetzt, und dennoch benötigen Sie eine ExecutorServicepro Anwendung.

ExecutorServiceVerschieben Sie die ExecutorService-Verwaltung (Erstellung / Herunterfahren) in Ihren benutzerdefinierten Service, anstatt den Status der Aktivitätslebenszyklusmethoden zu verwalten .

Erstellen Sie ExecutorServicein Service => onCreate()und fahren Sie es ordnungsgemäß herunteronDestroy()

Empfohlene Art des Herunterfahrens ExecutorService:

So beenden Sie Java ExecutorService ordnungsgemäß

Ravindra Babu
quelle
3

Ein ExecutorService sollte heruntergefahren werden, sobald er nicht mehr benötigt wird, um Systemressourcen freizugeben und ein ordnungsgemäßes Herunterfahren der Anwendung zu ermöglichen. Da es sich bei den Threads in einem ExecutorService möglicherweise um Nondaemon-Threads handelt, können sie die normale Beendigung der Anwendung verhindern. Mit anderen Worten, Ihre Anwendung bleibt nach Abschluss der Hauptmethode ausgeführt.

Nachschlagewerk

Chaper: 14 Seite: 814

Emon
quelle
0

Grund für den Aufruf von shutdown () in ExecutorService

Heute bin ich auf eine Situation gestoßen, in der ich warten muss, bis eine Maschine bereit ist, bevor ich eine Reihe von Aufgaben auf dieser Maschine starte.

Ich rufe diesen Computer erneut an. Wenn ich 503 (Server nicht verfügbar) nicht erhalte, ist der Computer bereit, meine Anforderungen zu verarbeiten. Also warte ich, bis ich 200 (Erfolg) für den ersten REST-Aufruf erhalte.

Es gibt mehrere Möglichkeiten, dies zu erreichen. Ich habe ExecutorService verwendet, um einen Thread zu erstellen, und die Ausführung nach jeweils X Sekunden geplant. Also muss ich diesen Thread unter einer Bedingung stoppen, check this out ...

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);

Zweite Nebenfrage, etwas kleiner befasst sich mit Android-Plattform.

Vielleicht kann ich antworten, wenn Sie etwas mehr Kontext bereitstellen! Auch aus meiner Erfahrung mit der Android-Entwicklung ist es selten, dass Sie Threads benötigen. Entwickeln Sie ein Spiel oder eine App, die Threads für die Leistung benötigt? Wenn nicht, haben Sie in Android andere Möglichkeiten, um Probleme zu lösen, wie das oben erläuterte Szenario. Sie können TimerTask, AsyncTask oder Handler oder Loader je nach Kontext verwenden. Dies liegt daran, dass Sie wissen, was passiert, wenn UIThread lange wartet: /

Pruthvidhar Rao Nadunooru
quelle
0

Dies gilt ungeachtet für geplante Unternehmen, z. B. für einen ScheduledExecutorService: Neue Fälle der gebuchten Aufgabe werden nicht ausgeführt.

Wir sollten erwarten, dass Sie eine Komfortanwendung haben, bei der eine Agentenverwaltung N Besorgungen ausführt.

Ich verstehe nicht, dass es mühelos bedeutet? Möglicherweise muss Ihre Bewerbung nicht die Option haben, weitere Aufträge an die Agentenverwaltung zu senden, und in der Zwischenzeit müssen Sie fest sitzen, damit Ihre aktuellen N-Verpflichtungen abgeschlossen sind.

Außer wenn Sie sich absolut sicher sind, dass Ihre Besorgungen am Ende erledigt sind, sollten Sie für eine bestimmte Pause fest sitzen und danach einfach aussteigen und die laufenden Saiten verlassen.

Für den Fall, dass Ihre Aktivitäten auf Störungen reagieren sollen, funktioniert dies einwandfrei.

Eine weitere interessante Situation ist der Punkt, an dem Sie einen ScheduledExecutorService haben, der eine Aktivität ausführt.

Der beste Weg, um die Aktivitätskette zu stoppen, besteht darin, shutdown () aufzurufen.

Devlax
quelle