2014-11-27 12 views
5

C'è una domanda con risposta su Best Way to Gracefully Shutdown a Java Command Line Program. Un hook di spegnimento esegue il lavoro nel caso in cui un programma sia stato terminato da Ctrl + C.Come arrestare con garbo un'applicazione Java che viene interrotta in seguito alla chiusura della riga di comando da cui è stata eseguita?

La mia domanda è come uscire con garbo se la riga di comando stessa viene chiusa durante l'esecuzione di un programma Java? Ho provato con il gancio di arresto, ma in questo caso non ha funzionato. Non riesco a scoprire cosa succede alla macchina virtuale in questo scenario. Il processo e tutti i suoi fili vengono uccisi all'istante? Che tipo di segnale produce la linea di comando di chiusura?

Quindi, come questo problema particolare può essere risolto?

MODIFICA: il problema riguarda l'ambiente Windows.

+0

Rispondi http://stackoverflow.com/a/20568883/4428150 spiega come farlo da C. – Gustave

risposta

2

Logicamente, SIGHUP (blocco del terminale) deve essere attivato.

In realtà, ho appena controllato la mia ipotesi con un semplice script di shell. Sì, quando un utente chiude un emulatore di terminale in cui è stata avviata un'applicazione (e dalla quale non è stato rimosso), l'applicazione riceve SIGHUP. Quindi imposta un gestore SIGHUP e reagisci di conseguenza. Un comportamento normale è quello di terminare un'applicazione, ma i tuoi intenti potrebbero essere diversi.

Anche se l'applicazione Java esegue operazioni STDIN/STDOUT, dovrebbe essere chiusa o almeno riconfigurata quando viene ricevuto HUP, perché un tentativo di lettura/scrittura da terminale non esistente potrebbe portare a SIGPIPE e/o programma bloccare.

Per Windows dare un'occhiata a Catch Windows terminal closing on running process

+0

Ho modificato la mia domanda. Inizialmente ho confuso i comandi di kill basati su Linux e Windows. In realtà, sono particolarmente interessato alla versione Windows di questo scenario. –

+0

"Riga comandi Windows" - cmd.exe? – user3159253

+0

Sì, mi riferivo a cmd.exe –

0

Modifica per le finestre ambiente:

Non ho molta esperienza in ambiente Windows, ma se si desidera che l'applicazione per continuare a correre, è generalmente implementato come servizio di Windows (è simile a daemon su Linux). In genere, avvii/fermi/riavvii il servizio tramite un'utility che elenca tutti i servizi (penso che ci arrivi tramite il pannello di controllo -> Strumenti di amministrazione -> Servizi. Direi che emettere un "stop" tramite questo strumento significherebbe un aggraziato l'arresto. e se si uccide il servizio tramite il task manager, allora non sarà un arresto regolare.


si tratta di un ambiente basato su Windows Linux basata o? in Linux, se è stato eseguito il programma in background (ed esce dalla shell con il comando 'exit'), continuerà a funzionare.Potrai mettere l'applicazione in background aggiungendo un & alla fine.Inoltre, molte applicazioni/servizi vengono eseguite in background. uno script di avvio di Tomcat con il comando startup.sh, continuerà a funzionare anche in background n esci dal terminale dal quale l'hai lanciato. Anche su Windows, il concetto dovrebbe essere simile.

In termini di chiusura dell'applicazione, si utilizza il comando kill sui sistemi Linux. il comando kill su un processo invia ad esso un segnale SIGTERM. Le applicazioni possono implementare il codice per intercettare SIGTERM e arrestare con garbo il rilevamento di un SIGTERM. Se l'applicazione non gestisce SIGTERM con garbo, allora non risponderà a un SIGTERM/kill. In tal caso, devi dargli esplicitamente un SIGKILL (kill -9) per ucciderlo con forza. In tal caso, l'arresto regolare non è possibile.

+0

"se si esegue il programma in background, continuerà a essere eseguito anche se si chiude il terminale" non è necessariamente così. – user3159253

+0

hai ragione. aggiornerò il mio commento. – Jigish

+0

Non dimentichiamo nohup senza il quale ciò che suggerisci non sarebbe vero. – Khanna111

0

In Java, esiste un metodo speciale Runtime: addShutdownHook.

Ciò consente di inizializzare un thread che la JVM tenterà di eseguire appena prima dell'arresto.È il posto dove inserire qualsiasi ripulitura che si desidera eseguire anche in caso di Ctrl-C di chiusura della finestra genitore. Estratto da javadoc: Un hook di arresto è semplicemente un thread inizializzato ma non avviato. Quando la macchina virtuale inizia la sua sequenza di spegnimento, avvierà tutti i ganci di arresto registrati in un ordine non specificato e li lascerà correre simultaneamente. Al termine di tutti gli hook, eseguirà tutti i finalizzatori non inviati se la finalizzazione all'uscita è stata abilitata. Alla fine, la macchina virtuale si fermerà.

Il gancio di arresto viene chiamato anche se il programma termina normalmente. In questo caso, è più pulita per rimuovere il gancio registrato prima di uscire con removeShutdownHook (ancora un metodo da Runtime)

EDIT:

nel caso di ambiente Windows, non ci sono segnali reali, ma callback speciali quando il sistema si sta spegnendo. AFAIK, l'hook di sistema viene chiamato correttamente in quel caso, ma ammetto che non l'ho mai provato. In Windows, i processi possono essere chiesto di interrompere con 2 modi:

  • messaggi di funzione PostQuitMessage un messaggio WM_QUIT nel processo di ciclo di eventi - normalmente il processo dovrebbe uscire, ma si può fare la sua pulizia (equivallent di Unix SIG_TERM)
  • TerminateProcess arresta immediatamente il processo e tutti i suoi fili (equivallent di Unix SIG_KILL)

processi console possono utilizzare un ConsoleControlHandler che può intercettare Ctrl-C, Ctrl-break o Ctrl-eventi Chiusura. I primi due vengono generati tramite tastiera, l'ultimo viene generato quando l'utente chiude la console. Normalmente, Oracle JVM dovrebbe utilizzare il meccanismo di hook del sistema quando ottiene l'evento Ctrl-Close che viene elaborato allo stesso modo di un SIGTERM.

+0

Ho citato il gancio di arresto nella mia domanda. Ha funzionato in caso di Ctrl-C, ma non ha funzionato in caso di chiusura di cmd.exe –

Problemi correlati