web-dev-qa-db-fra.com

Exemple utile d'un crochet d'arrêt en Java?

J'essaie de m'assurer que mon Java application prend des mesures raisonnables pour être robuste), ce qui implique notamment l'arrêt du système en douceur. Je lis à propos de hooks d'arrêt et moi ne comprennent pas vraiment comment les utiliser dans la pratique.

Existe-t-il un exemple concret?

Disons que j'ai une application très simple comme celle-ci ci-dessous, qui écrit des nombres dans un fichier, 10 dans 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 crochet d'arrêt mais je ne sais pas comment l'intégrer à 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();
        }
    }
}
119
Jason S

Vous pouvez faire ce qui suit:

  • Laissez le crochet d’arrêt définir une valeur de "keepRunning" sur AtomicBoolean (ou un booléen volatil)
  • (Facultativement, .interrupt Les threads de travail s’ils attendent des données dans un appel bloquant)
  • Attendez la fin des threads de travail (en exécutant writeBatch dans votre cas) en appelant la méthode Thread.join() sur les threads de travail.
  • Terminer le programme

Un code peu précis:

  • Ajouter un static volatile boolean keepRunning = true;
  • Dans run () vous passez à

    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 un "rejeter gracieusement tous les clients en frappant Control-C" dans le terminal.


De les docs :

Lorsque la machine virtuelle commence sa séquence d'arrêt, elle lancera tous les points d'ancrage d'arrêt enregistrés dans un ordre non spécifié et les laissera s'exécuter simultanément. Une fois tous les points d'accroche 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 point d’arrêt maintient la machine virtuelle Java en fonctionnement jusqu’à ce qu’il soit terminé (renvoyé de la méthode run () -.

150
aioobe