Capturando Ctrl + C en Java

80

¿Es posible captar la señal Ctrl+ Cen una aplicación de línea de comandos de Java? Me gustaría limpiar algunos recursos antes de terminar el programa.

Pierre
fuente

Respuestas:

89

Puede adjuntar un gancho de apagado a la VM que se ejecuta cada vez que la VM se apaga:

La máquina virtual Java se apaga en respuesta a dos tipos de eventos:

  • El programa sale normalmente, cuando sale el último subproceso que no es demonio o cuando se invoca el método de salida (equivalentemente, System.exit), o

  • La máquina virtual se termina en respuesta a una interrupción del usuario, como escribir Ctrl+ C, o un evento en todo el sistema, como el cierre de sesión del usuario o el apagado del sistema.

Sin embargo, el hilo que pasa como gancho de cierre tiene que seguir varias reglas, así que lea la documentación vinculada con atención para evitar cualquier problema. Esto incluye garantizar la seguridad del hilo, la terminación rápida del hilo, etc.

Además, como señala el comentarista Jesper, se garantiza que los ganchos de cierre se ejecuten en el cierre normal de la máquina virtual, pero si el proceso de la máquina virtual se termina por la fuerza, no es así. Esto puede suceder si el código nativo se estropea o si mata a la fuerza el proceso ( kill -9, taskkill /f).

Pero en esos escenarios, todas las apuestas están canceladas de todos modos, por lo que no desperdiciaría mucho pensamiento en ello.

Joey
fuente
1
Tenga en cuenta que no se garantiza que los ganchos de cierre se ejecuten en todas las circunstancias; puede haber situaciones en las que no se ejecuten, así que no haga que el funcionamiento correcto de su programa dependa de lo que haga en un gancho de cierre.
Jesper
4
No se ejecutan, cuando el proceso finaliza con fuerza ( TerminateProcess()o SIGKILL) pero eso está fuera del funcionamiento normal y, dado que Ctrl + C ya está cubierto por el gancho de cierre, es seguro usarlo. No puede hacer mucho si el sistema operativo realmente termina su proceso de todos modos.
Joey
1
kill -HUPes la eliminación "más suave" de Unix y debería ejecutar el gancho de cierre. No estoy seguro del valor predeterminado kill.
livefree75
1
La eliminación predeterminada hace que el gancho de apagado se ejecute en mi máquina (Redhat 7.3). Kill -9 no lo hace.
MikeKulls
2
No se garantiza que los ganchos de cierre se ejecuten en ningún orden en particular, por lo que si su gancho de cierre se basa en otros ganchos de cierre que aún no se ejecutan (o viceversa), puede tener problemas.
Luke Hutchison
28

Solo para fines de prueba rápida de la consola ...

Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            try {
                Thread.sleep(200);
                System.out.println("Shutting down ...");
                //some cleaning up code...

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        }
    });
bkomac
fuente
0

La respuesta principal sugiere usar un gancho de cierre. Los ganchos de cierre son mucho más problemáticos de lo que valen. Se ejecutan en un orden indeterminado, y las bibliotecas de las que depende pueden agregar sus propios enlaces de cierre, lo que puede significar que algo de lo que depende su propio enlace de cierre se puede desinicializar antes de que se ejecute el enlace de cierre. Ahórrese el dolor de cabeza y use un controlador de señales:

Signal.handle(new Signal("INT"),  // SIGINT
    signal -> System.out.println("Interrupted by Ctrl+C"));

Signales actualmente sun.misc.Signal, lo que significa que quedará obsoleto, pero el nombre por el que se está reemplazando se llama actualmente jdk.internal.misc.Signal, por lo que hasta que el equipo de Java descubra cómo exponer públicamente los controladores de señales de una manera no interna, tenga en cuenta que esta llamada puede desaparecer. Sin embargo, por ahora (a partir de JDK 11), sun.misc.Signaltodavía existe.

Luke Hutchison
fuente