Domanda

Sto cercando di assicurarsi che la mia applicazione Java prende misure ragionevoli per essere robusta, e parte di questo comporta la chiusura con grazia. Sto leggendo sui ganci di arresto e io in realtà non ottengono come fare uso di loro in pratica.

C'è un esempio pratico là fuori?

Diciamo che ho avuto davvero una semplice applicazione come questa qui sotto, che scrive i numeri in un file, 10 ad una linea, in lotti di 100, e voglio per assicurarsi che un dato finiture in batch se il programma viene interrotto. Ottengo come registrare un gancio di arresto, ma non ho idea di come integrare che nella mia applicazione. Qualche suggerimento?

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();
        }
    }
}
È stato utile?

Soluzione

Si potrebbe fare la seguente:

  • Sia il gancio di arresto impostato alcuni AtomicBoolean (o booleano volatile) "keepRunning" false
  • (Opzionalmente, .interrupt i fili di lavoro se aspettano per i dati in qualche blocco delle chiamate)
  • Attendere che i fili di lavoro (esecuzione writeBatch nel tuo caso) alla fine, chiamando il metodo Thread.join() sui filetti di lavoro.
  • Termina il programma

Alcuni codice abbozzato:

  • Aggiungi un static volatile boolean keepRunning = true;
  • run () si cambia a

    for (int i = 0; i < N && keepRunning; ++i)
        writeBatch(pw, i);
    
  • main () si aggiunge:

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

Questo è più o meno come lo faccio una graziosa "rifiutare tutti i clienti al momento di colpire Control-C" nel terminale.


Da la documentazione :

  

Quando la macchina virtuale inizia la sua sequenza di chiusura inizierà tutti i ganci di arresto registrati in un ordine specificato e farli eseguiti contemporaneamente. Quando tutti i ganci hanno finito sarà quindi eseguire tutti i finalizzatori uninvoked se finalizzazione-on-uscita è stata abilitata. Infine, la macchina virtuale si fermerà.

Cioè, un gancio di arresto mantiene la JVM finché il gancio ha terminato (restituito dal run () -method.

Altri suggerimenti

ganci di arresto sono fili unstarted registrati con Runtime.addShutdownHook () JVM non fornisce alcuna garanzia sull'ordine in cui i ganci di arresto sono started.For maggiori informazioni riferimento http://techno-terminal.blogspot.in/2015/08/shutdown-hooks.html

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top