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?
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...");
}
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 appelantshutdownNow
, 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();
}
}