Aggiunta di hook di arresto per applicazioni JVM

1. Panoramica

In genere è facile avviare un servizio. Tuttavia, a volte abbiamo bisogno di avere un piano per chiuderne uno con garbo.

In questo tutorial, daremo uno sguardo ai diversi modi in cui un'applicazione JVM può terminare. Quindi, utilizzeremo le API Java per gestire gli hook di chiusura JVM. Fare riferimento a questo articolo per ulteriori informazioni sull'arresto della JVM nelle applicazioni Java.

2. Arresto JVM

La JVM può essere chiusa in due modi diversi:

  1. Un processo controllato
  2. Un modo brusco

Un processo controllato arresta la JVM quando:

  • L'ultimo thread non daemon termina. Ad esempio, quando il thread principale esce, la JVM avvia il processo di arresto
  • Invio di un segnale di interruzione dal sistema operativo. Ad esempio, premendo Ctrl + C o disconnettendosi dal sistema operativo
  • Chiamare System.exit () dal codice Java

Sebbene ci sforziamo tutti per arresti graziosi, a volte la JVM può spegnersi in modo brusco e inaspettato. La JVM si spegne improvvisamente quando :

  • Invio di un segnale di kill dal sistema operativo. Ad esempio, emettendo un kill -9
  • Richiamo di Runtime.getRuntime (). Halt () dal codice Java
  • Il sistema operativo host muore inaspettatamente, ad esempio, in caso di interruzione di corrente o panico del sistema operativo

3. Ganci di arresto

La JVM consente di eseguire la registrazione delle funzioni prima del completamento dell'arresto. Queste funzioni sono generalmente un buon posto per rilasciare risorse o altre attività di manutenzione domestica simili. Nella terminologia JVM, queste funzioni sono chiamate hook hutdown .

Gli hook di arresto sono fondamentalmente thread inizializzati ma non avviati . Quando la JVM inizia il processo di chiusura, avvierà tutti gli hook registrati in un ordine non specificato. Dopo aver eseguito tutti gli hook, la JVM si arresterà.

3.1. Aggiunta di ganci

Per aggiungere un hook di spegnimento, possiamo utilizzare il metodo Runtime.getRuntime (). AddShutdownHook () :

Thread printingHook = new Thread(() -> System.out.println("In the middle of a shutdown")); Runtime.getRuntime().addShutdownHook(printingHook);

Qui stampiamo semplicemente qualcosa sullo standard output prima che JVM si spenga da solo. Se chiudiamo la JVM come segue:

> System.exit(129); In the middle of a shutdown

Quindi vedremo che l'hook effettivamente stampa il messaggio sullo standard output.

La JVM è responsabile dell'avvio dei thread hook . Pertanto, se il dato hook è già stato avviato, Java genererà un'eccezione:

Thread longRunningHook = new Thread(() -> { try { Thread.sleep(300); } catch (InterruptedException ignored) {} }); longRunningHook.start(); assertThatThrownBy(() -> Runtime.getRuntime().addShutdownHook(longRunningHook)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Hook already running"); 

Ovviamente, non possiamo nemmeno registrare un hook più volte:

Thread unfortunateHook = new Thread(() -> {}); Runtime.getRuntime().addShutdownHook(unfortunateHook); assertThatThrownBy(() -> Runtime.getRuntime().addShutdownHook(unfortunateHook)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Hook previously registered");

3.2. Rimozione dei ganci

Java fornisce una doppia remove metodo per rimuovere un particolare gancio di arresto dopo registrarlo:

Thread willNotRun = new Thread(() -> System.out.println("Won't run!")); Runtime.getRuntime().addShutdownHook(willNotRun); assertThat(Runtime.getRuntime().removeShutdownHook(willNotRun)).isTrue(); 

Il metodo removeShutdownHook () restituisce true quando l'hook di spegnimento viene rimosso con successo.

3.3. Avvertenze

La JVM esegue gli hook di chiusura solo in caso di terminazioni normali. Quindi, quando una forza esterna interrompe improvvisamente il processo JVM, la JVM non avrà la possibilità di eseguire gli hook di arresto. Inoltre, anche l'arresto della JVM dal codice Java avrà lo stesso effetto:

Thread haltedHook = new Thread(() -> System.out.println("Halted abruptly")); Runtime.getRuntime().addShutdownHook(haltedHook); Runtime.getRuntime().halt(129); 

Il metodo halt termina forzatamente la JVM attualmente in esecuzione. Pertanto, gli hook di arresto registrati non avranno la possibilità di essere eseguiti.

4. Conclusione

In questo tutorial, abbiamo esaminato diversi modi in cui un'applicazione JVM può eventualmente terminare. Quindi, abbiamo utilizzato alcune API di runtime per registrare e annullare la registrazione degli hook di chiusura.

Come al solito, il codice di esempio è disponibile su GitHub.