Exemple utile d’un hook d’arrêt en Java?

J’essaie de m’assurer que mon application Java prend des mesures raisonnables pour être robuste, et une partie de cela consiste à arrêter normalement. Je lis des articles sur les hooks d’arrêt et je ne comprends pas comment les utiliser en pratique.

Existe-t-il un exemple pratique?

Disons que j’ai une application très simple comme celle-ci ci-dessous, qui écrit des nombres dans un fichier, 10 à une ligne, par lots de 100, et je veux m’assurer qu’un lot donné se termine si le programme est interrompu. Je comprends comment enregistrer un hook d’arrêt, mais je n’ai aucune idée de comment l’intégrer dans mon application. Aucune suggestion?

package com.example.test.concurrency; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintWriter; public class GracefulShutdownTest1 { final private int N; final private File f; public GracefulShutdownTest1(File f, int N) { this.f=f; this.N = N; } public void run() { PrintWriter pw = null; try { FileOutputStream fos = new FileOutputStream(this.f); pw = new PrintWriter(fos); for (int i = 0; i < N; ++i) writeBatch(pw, i); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { pw.close(); } } private void writeBatch(PrintWriter pw, int i) { for (int j = 0; j < 100; ++j) { int k = i*100+j; pw.write(Integer.toString(k)); if ((j+1)%10 == 0) pw.write('\n'); else pw.write(' '); } } static public void main(String[] args) { if (args.length < 2) { System.out.println("args = [file] [N] " +"where file = output filename, N=batch count"); } else { new GracefulShutdownTest1( new File(args[0]), Integer.parseInt(args[1]) ).run(); } } } 

Vous pouvez faire ce qui suit:

  • Laissez le hook d’arrêt mettre une valeur AtomicBoolean (ou booléenne volatile) “keepRunning” à false
  • (Éventuellement, .interrupt les threads de travail s’ils attendent des données dans un appel bloquant)
  • Attendez la fin des threads de travail (exécutant writeBatch dans votre cas) en appelant la méthode Thread.join() sur les threads de travail.
  • Terminer le programme

Un code sommaire:

  • Ajoutez un static volatile boolean keepRunning = true;
  • En cours d’ exécution (), vous changez pour

     for (int i = 0; i < N && keepRunning; ++i) writeBatch(pw, i); 
  • Dans main () vous ajoutez:

     final Thread mainThread = Thread.currentThread(); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { keepRunning = false; mainThread.join(); } }); 

C'est à peu près comme ça que je fais gracieusement "rejeter tous les clients en appuyant sur Control-C" dans le terminal.


De la documentation :

Lorsque la machine virtuelle commence sa séquence d'arrêt, elle démarre tous les hooks d'arrêt enregistrés dans un ordre non spécifié et les laisse s'exécuter simultanément. Une fois tous les hooks terminés, tous les finaliseurs non invoqués seront exécutés si la finalisation à la sortie a été activée. Enfin, la machine virtuelle s'arrêtera.

En d'autres termes, un hook d'arrêt maintient la JVM en cours d'exécution jusqu'à ce que le hook soit terminé (renvoyé par la méthode run ()) .

Les crochets d’arrêt sont des threads non démarrés enregistrés avec Runtime.addShutdownHook (). JVM ne donne aucune garantie sur l’ordre dans lequel les hooks d’arrêt sont démarrés. Pour plus d’informations, consultez http://techno-terminal.blogspot.in/2015/08 /shutdown-hooks.html