web-dev-qa-db-fra.com

Raison de l'appel de shutdown () sur ExecutorService

J'en ai lu pas mal au cours des dernières heures, et je ne vois tout simplement aucune raison (raison valable) d'appeler shutdown() sur la ExecutorService, à moins que nous ayons une énorme application qui stocke des dizaines et des dizaines de services d'exécution différents qui ne utilisé depuis longtemps.

La seule chose (d'après ce que je comprends) que l'arrêt fait, est de faire ce qu'un thread normal fait une fois que c'est fait. Lorsque le thread normal termine la méthode d'exécution de Runnable (ou Callable), il est transmis à la récupération de place pour qu'il soit collecté. Avec Executor Service, les threads seront simplement mis en attente, ils ne seront pas cochés pour la récupération de place. Pour cela, l'arrêt est nécessaire.

Ok, revenons à ma question. Existe-t-il une raison d'appeler la fermeture de ExecutorService très souvent, ou même juste après l'avoir soumise à certaines tâches? Je voudrais laisser le cas derrière quelqu'un le fait et juste après cela appelle à awaitTermination() car cela est validé. Une fois que nous avons fait cela, nous devons recréer une nouvelle ExecutorService à nouveau, pour faire la même chose. N'est-ce pas l'idée même pour la ExecutorService de réutiliser les threads? Alors pourquoi détruire la ExecutorService si tôt?

N’est-ce pas une façon rationnelle de créer simplement ExecutorService (ou un couple en fonction du nombre dont vous avez besoin), puis pendant l'exécution de l'application, laissez-leur passer les tâches une fois qu'elles sont arrivées, puis à la sortie de l'application ou à d'autres étapes importantes exécuteurs?

J'aimerais connaître les réponses de certains programmeurs expérimentés qui écrivent beaucoup de code asynchrone à l'aide de ExecutorServices.

Deuxième question secondaire, des offres un peu plus petites avec la plateforme Android. SI certains d’entre vous diront que ce n’est pas la meilleure idée d’arrêter les exécuteurs à chaque fois et que vous programmez sur Android, pouvez-vous me dire comment gérer ces arrêts (pour être précis - quand vous les exécutez) lorsque nous traitons différents événements de cycle de vie de l'application.

A cause du commentaire de CommonsWare, j'ai rendu le post neutre. Je ne suis vraiment pas intéressé à en discuter à mort et il semble que cela mène là-bas. Je suis seulement intéressé à apprendre ce que j'ai demandé ici à des développeurs expérimentés, s'ils sont disposés à partager leurs expériences. Merci.

64
Lucas

La méthode shutdown() fait une chose: empêche les clients d’envoyer davantage de travail au service de l’exécuteur. Cela signifie que toutes les tâches existantes seront exécutées jusqu'à ce que d'autres actions soient entreprises. Cela est vrai même pour les tâches planifiées, par exemple, pour un ScheduledExecutorService: les nouvelles instances de la tâche planifiée ne seront pas exécutées. Cela peut être utile dans différents scénarios.

Supposons que vous avez une application console qui a un service exécuteur exécutant N tâches. Si l'utilisateur appuie sur CTRL-C, vous vous attendez à ce que l'application se termine, éventuellement de manière élégante. Qu'est-ce que cela signifie gracieusement? Vous souhaitez peut-être que votre application ne puisse pas soumettre davantage de tâches au service de l'exécutant tout en attendant la fin de vos tâches N existantes. Pour ce faire, vous pouvez utiliser un crochet d'arrêt en dernier recours:

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

Ce raccordement arrêtera le service, ce qui empêchera votre application de soumettre de nouvelles tâches et attendra que toutes les tâches existantes se terminent avant d'arrêter la machine virtuelle. La fin de l'attente sera bloquée pendant 5 secondes et retournera true si le service est arrêté. Cette opération est effectuée en boucle afin que vous soyez sûr que le service sera éventuellement arrêté. L'InterruptedException est avalé à chaque fois. C’est le meilleur moyen d’arrêter un service d’exécuteur réutilisé dans l’ensemble de votre application.

Ce code n'est pas parfait. Sauf si vous êtes absolument certain que vos tâches finiront par se terminer, vous voudrez peut-être attendre un délai donné, puis simplement quitter, en abandonnant les threads en cours d'exécution. Dans ce cas, il serait judicieux d'appeler également shutdownNow() après le délai d'attente lors d'une dernière tentative d'interruption des tâches en cours d'exécution (shutdownNow() vous donnera également une liste des tâches en attente d'exécution). Si vos tâches sont conçues pour répondre à une interruption, cela fonctionnera correctement.

Un autre scénario intéressant est lorsque vous avez un ScheduledExecutorService qui effectue une tâche périodique. Le seul moyen d'arrêter la chaîne de tâches périodiques consiste à appeler shutdown().

EDIT: J'aimerais ajouter que je ne recommanderais pas d'utiliser un crochet d'arrêt comme indiqué ci-dessus dans le cas général: il peut être sujet à des erreurs et ne doit être utilisé qu'en dernier recours. De plus, si vous avez enregistré plusieurs crochets d'arrêt, l'ordre dans lequel ils seront exécutés n'est pas défini, ce qui peut être indésirable. Je préférerais que l'application appelle explicitement shutdown() sur InterruptedException.

38
Giovanni Botta

ExecutorService n’a-t-il pas l’idée de réutiliser les threads? Alors pourquoi détruire ExecutorService si tôt?

Oui. Vous ne devez pas détruire et recréer ExecutorService fréquemment. Initialisez ExecutorService lorsque vous en avez besoin (surtout au démarrage) et laissez-la active jusqu'à ce que vous en ayez fini. 

N’est-ce pas une façon rationnelle de créer simplement ExecutorService (ou un couple en fonction du nombre dont vous avez besoin), puis, pendant l'exécution de l'application, passez-leur les tâches une fois qu'elles sont arrivées, puis à la sortie de l'application ou à d'autres étapes importantes exécuteurs?

Oui. Il est rationnel d'arrêter ExecutorService sur des étapes importantes telles que la sortie de l'application, etc. 

Deuxième question secondaire, des offres un peu plus petites avec la plateforme Android. SI certains d’entre vous diront que ce n’est pas la meilleure idée d’arrêter les exécuteurs à chaque fois et que vous programmez sur Android, pourriez-vous me dire comment vous gérez ces arrêts (pour être précis, quand vous les exécutez) lorsque nous traitons différents événements d’application cycle de la vie.

Supposons que ExecutorService soit partagé entre différentes activités de votre application. Chaque activité sera suspendue/reprise à des intervalles de temps différents et vous aurez toujours besoin d’une ExecutorService par application.

Au lieu de gérer l'état de ExecutorService dans les méthodes de cycle de vie d'activité, déplacez la gestion ExecutorService (Création/Fermeture) vers votre client Service .

Créez ExecutorService dans Service => onCreate() et arrêtez-le correctement dans onDestroy()

Manière recommandée de fermer ExecutorService:

Comment arrêter correctement Java ExecutorService

5
Ravindra babu

Un ExecutorService doit être arrêté lorsqu'il n'est plus nécessaire libérer des ressources système et permettre un arrêt progressif des applications . Parce que les threads d'un ExecutorService peuvent être des threads non désaemon, ils peuvent empêcher la fermeture normale d'une application. En d'autres termes, votre l'application reste en cours d'exécution une fois sa méthode principale terminée.

Livre de référence

Chaper: 14 Page: 814

1
emon

Ceci est vrai nonobstant pour les engagements planifiés, par exemple pour un ScheduledExecutorService: les nouveaux cas de l’affectation réservée ne seront pas exécutés.

Nous nous attendons à ce que vous ayez une application confortable avec une administration d’agent exécutant N courses.

Je ne comprends pas que ça veut dire sans effort? Peut-être avez-vous besoin que votre application n'ait pas la possibilité de soumettre plus de missions à l'administration des agents et qu'entre-temps, vous devez rester attentif pour que vos engagements N actuels soient terminés.

Sauf si vous êtes totalement certain que vos courses le seront à la fin, vous devriez vous asseoir serré pendant une pause et après cela, il vous suffit de sortir, en abandonnant les ficelles.

Si vos activités sont censées réagir aux interférences, cela fonctionnera correctement.

Une autre situation intéressante est le moment où vous avez un ScheduledExecutorService qui exécute une activité.

Le meilleur moyen d'arrêter la chaîne d'activité est d'appeler shutdown ()

0
Devlax

Raison de l'appel de shutdown () sur ExecutorService

Aujourd'hui, j'ai rencontré une situation dans laquelle je devais attendre qu'une machine soit prête avant de commencer une série de tâches sur cette machine.

Je passe un appel REST à cette machine. Si je ne reçois pas 503 (serveur indisponible), la machine est prête à traiter mes demandes. J'attends donc 200 (Succès) pour le premier appel REST.

Il y a plusieurs façons de le réaliser, j'ai utilisé ExecutorService pour créer un thread et l'a programmé pour s'exécuter après chaque X secondes. Donc, je dois arrêter ce fil sur une condition, consultez ceci ...

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

Deuxième question secondaire, des offres un peu plus petites avec la plate-forme Android.

Je peux peut-être répondre si vous fournissez un peu plus de contexte! .__ De plus, d'après mon expérience du développement Android, il est rare que vous ayez besoin de Threads. Développez-vous un jeu ou une application qui nécessite des threads pour la performance? Sinon, dans Android, vous avez d'autres moyens de résoudre des problèmes comme le scénario que j'ai expliqué ci-dessus. Vous pouvez plutôt utiliser TimerTask, AsyncTask ou Handlers ou Loaders en fonction du contexte. En effet, si UIThread attend longtemps, vous savez ce qui se passe: /