web-dev-qa-db-fra.com

Comment arrêter un ExecutorService?

Chaque fois que j'appelle shutdownNow() ou shutdown(), il ne s'arrête pas. J'ai lu quelques discussions où il était dit que la fermeture n'est pas garantie - quelqu'un peut-il me fournir un bon moyen de le faire?

39
rosesr

Le modèle typique est:

executorService.shutdownNow();
executorService.awaitTermination();

Lors de l'appel de shutdownNow, l'exécuteur tentera (généralement) d'interrompre les threads qu'il gère. Pour rendre l'arrêt progressif, vous devez intercepter l'exception interrompue dans les threads ou vérifier l'état interrompu. Si vous ne le faites pas, vos threads s'exécuteront pour toujours et votre exécuteur ne pourra jamais s'arrêter. En effet, l'interruption des threads dans Java est un processus collaboratif (c'est-à-dire que le code interromp doit faire quelque chose lorsqu'on lui demande d'arrêter, pas le interruption) code).

Par exemple, le code suivant imprime Exiting normally.... Mais si vous commentez la ligne if (Thread.currentThread().isInterrupted()) break;, elle affichera Still waiting... Car les threads de l'exécuteur sont toujours en cours d'exécution.

public static void main(String args[]) throws InterruptedException {
    ExecutorService executor = Executors.newFixedThreadPool(1);
    executor.submit(new Runnable() {

        @Override
        public void run() {
            while (true) {
                if (Thread.currentThread().isInterrupted()) break;
            }
        }
    });

    executor.shutdownNow();
    if (!executor.awaitTermination(100, TimeUnit.MICROSECONDS)) {
        System.out.println("Still waiting...");
        System.exit(0);
    }
    System.out.println("Exiting normally...");
}

Alternativement, il pourrait être écrit avec un InterruptedException comme ceci:

public static void main(String args[]) throws InterruptedException {
    ExecutorService executor = Executors.newFixedThreadPool(1);
    executor.submit(new Runnable() {

        @Override
        public void run() {
            try {
                while (true) {Thread.sleep(10);}
            } catch (InterruptedException e) {
                //ok let's get out of here
            }
        }
    });

    executor.shutdownNow();
    if (!executor.awaitTermination(100, TimeUnit.MICROSECONDS)) {
        System.out.println("Still waiting...");
        System.exit(0);
    }
    System.out.println("Exiting normally...");
}
83
assylias

La meilleure façon est ce que nous avons réellement dans le javadoc qui est:

La méthode suivante arrête un ExecutorService en deux phases, d'abord en appelant shutdown pour rejeter les tâches entrantes, puis en appelant shutdownNow, si nécessaire, pour annuler les tâches persistantes :

void shutdownAndAwaitTermination(ExecutorService pool) {
    pool.shutdown(); // Disable new tasks from being submitted
    try {
        // Wait a while for existing tasks to terminate
        if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
            pool.shutdownNow(); // Cancel currently executing tasks
            // Wait a while for tasks to respond to being cancelled
            if (!pool.awaitTermination(60, TimeUnit.SECONDS))
                System.err.println("Pool did not terminate");
        }
    } catch (InterruptedException ie) {
        // (Re-)Cancel if current thread also interrupted
        pool.shutdownNow();
        // Preserve interrupt status
        Thread.currentThread().interrupt();
    }
}
19
Nicolas Filotto