¿Cuándo deberíamos llamar a System.exit en Java?
exit(- 1); (10)
Aunque la respuesta fue realmente útil, pero de alguna manera se olvidó de algunos detalles adicionales. Espero que a continuación te ayude a comprender el proceso de cierre en Java, además de la respuesta anterior:
- En un apagado ordenado *, la JVM primero inicia todos los ganchos de apagado registrados. Los ganchos de cierre son hilos no iniciados que están registrados con Runtime.addShutdownHook.
- JVM no garantiza el orden en que se inician los ganchos de desconexión. Si alguno de los subprocesos de aplicación (daemon o no demonio) aún se está ejecutando en el momento del cierre, continúan ejecutándose al mismo tiempo que el proceso de apagado .
- Cuando se hayan completado todos los enganches de cierre, la JVM puede elegir ejecutar los finalizadores si runFinalizersOnExit es verdadero, y luego se detiene.
- JVM no intenta detener o interrumpir ningún subproceso de aplicación que aún se esté ejecutando en el momento del cierre; se terminan abruptamente cuando la JVM finalmente se detiene.
- Si los ganchos de cierre o finalizadores no se completan, entonces el proceso de apagado ordenado "se bloquea" y la JVM debe cerrarse abruptamente.
- En un cierre abrupto, la JVM no está obligada a hacer nada más que detener la JVM; los ganchos de cierre no se ejecutarán.
PD: La JVM puede cerrarse de manera ordenada o abrupta .
- Un cierre ordenado se inicia cuando finaliza el último subproceso "normal" (no demoníaco), alguien llama a System.exit o por otros medios específicos de plataforma (como enviar un SIGINT o presionar Ctrl-C).
- Si bien lo anterior es la forma estándar y preferida para que la JVM se cierre, también se puede cerrar abruptamente llamando a Runtime.halt o eliminando el proceso de JVM a través del sistema operativo (como el envío de un SIGKILL).
En Java, ¿cuál es la diferencia con System.exit(0)
o sin System.exit(0)
en el código siguiente?
public class TestExit
{
public static void main(String[] args)
{
System.out.println("hello world");
System.exit(0); // is it necessary? And when it must be called?
}
}
El document dice: "Este método nunca vuelve normalmente". Qué significa eso?
El método nunca regresa porque es el fin del mundo y ninguno de tus códigos se ejecutará a continuación.
Su aplicación, en su ejemplo, saldría de todos modos en el mismo lugar del código, pero si usa System.exit. tienes la opción de devolver un código personalizado al entorno, como, por ejemplo,
System.exit(42);
¿Quién va a hacer uso de tu código de salida? Una secuencia de comandos que llamó a la aplicación. Funciona en Windows, Unix y todos los demás entornos programables.
¿Por qué devolver un código? Para decir cosas como "No tuve éxito", "La base de datos no respondió".
Para ver cómo obtener el valor de un código de salida y usarlo en un script de shell de Unix o script de cmd de Windows, puede verificar esta respuesta en este sitio.
En aplicaciones que pueden tener ganchos de apagado complejos, este método no debe invocarse desde un hilo desconocido. System.exit
nunca sale normalmente porque la llamada se bloqueará hasta que finalice la JVM. Es como si el código que se está ejecutando tuviera el enchufe enchufado antes de que pueda terminar. Al llamar a System.exit
se iniciarán los ganchos de cierre del programa y cualquier hilo que llame a System.exit
se bloqueará hasta la finalización del programa. Esto tiene la consecuencia de que si el gancho de apagado envía a su vez una tarea al hilo desde el que se llamó a System.exit
, el programa se estancará.
Estoy manejando esto en mi código con lo siguiente:
public static void exit(final int status) {
new Thread("App-exit") {
@Override
public void run() {
System.exit(status);
}
}.start();
}
En ese caso, no es necesario. No se han iniciado subprocesos adicionales, no está cambiando el código de salida (que por defecto es 0), básicamente no tiene sentido.
Cuando los documentos dicen que el método nunca vuelve normalmente, significa que la línea de código subsiguiente es efectivamente inalcanzable, aunque el compilador no sepa que:
System.exit(0);
System.out.println("This line will never be reached");
O bien se lanzará una excepción, o la VM terminará antes de regresar. Nunca "solo regresará".
Es muy raro que valga la pena llamar a System.exit()
IME. Puede tener sentido si estás escribiendo una herramienta de línea de comando, y quieres indicar un error a través del código de salida en lugar de solo lanzar una excepción ... pero no puedo recordar la última vez que lo usé en el código de producción normal .
Si tiene otro programa ejecutándose en la JVM y usa System.exit, ese segundo programa también se cerrará. Imagine, por ejemplo, que ejecuta un trabajo Java en un nodo del clúster y que el programa Java que gestiona el nodo del clúster se ejecuta en la misma JVM. Si el trabajo usaría System.exit, no solo abandonaría el trabajo sino que también "cerraría el nodo completo". No podría enviar otro trabajo a ese nodo del clúster ya que el programa de administración se ha cerrado accidentalmente.
Por lo tanto, no use System.exit si desea poder controlar su programa desde otro programa java dentro de la misma JVM.
Use System.exit si desea cerrar la JVM completa a propósito y si desea aprovechar las posibilidades que se han descrito en las otras respuestas (por ejemplo, cierre de hooks: cierre de Java , valor de retorno distinto de cero para la línea de comando) llamadas: cómo obtener el estado de salida de un programa Java en el archivo por lotes de Windows ).
También eche un vistazo a Excepciones de tiempo de ejecución: System.exit (num) o ejecute RuntimeException desde main?
System.exit es necesario
- cuando desee devolver un código de error que no sea 0
- cuando desee salir de su programa desde algún lugar que no sea main ()
En su caso, hace exactamente lo mismo que el simple retorno-de-principal.
Uno NUNCA debe llamar a System.exit (0).
- Es un "goto" oculto, y "gotos" rompe el flujo de control. Confiar en los ganchos en este contexto es una asignación mental que todos los desarrolladores del equipo deben tener en cuenta.
- Salir del programa "normalmente" proporcionará el mismo código de salida al sistema operativo que System.exit (0). Entonces es redundante. Si su programa no puede salir "normalmente", su desarrollo se salió de control. Deberías tener siempre el control total del estado del sistema.
- Ocultas problemas de programación, como ejecutar subprocesos que no se detienen normalmente.
- Esto se refiere a 3 .: puede encontrar un estado de aplicación inconstante que interrumpe los hilos de manera anormal.
Por cierto: devolver otros códigos de retorno que no sean 0 tiene sentido si desea indicar la terminación anormal del programa.
La especificación del lenguaje Java dice que
Salida del programa
Un programa termina toda su actividad y se cierra cuando ocurre una de estas dos cosas:
Todos los hilos que no son hilos daemon terminan.
Algunos subprocesos invocan el método de salida de clase Runtime o clase System , y la operación de salida no está prohibida por el administrador de seguridad.
Significa que deberías usarlo cuando tengas un gran programa (bueno, al menos más grande que este) y quieras terminar su ejecución.
System.exit()
se puede utilizar para ejecutar los ganchos de cierre antes de que el programa se cierre . Esta es una forma conveniente de manejar el apagado en programas más grandes, donde todas las partes del programa no pueden (y no deberían) estar conscientes el uno del otro. Luego, si alguien quiere abandonar, simplemente puede llamar a System.exit()
, y los ganchos de apagado (si están configurados correctamente) se encargan de realizar todas las ceremonias de cierre necesarias, como cerrar archivos, liberar recursos, etc.
"Este método nunca vuelve normalmente". significa simplemente que el método no volverá; una vez que un hilo va allí, no volverá.
Otra manera, quizás más común, de abandonar un programa es simplemente llegar al final del método main
. Pero si hay algún subproceso que no sea demonio en ejecución, no se cerrarán y, por lo tanto, la JVM no se cerrará. Por lo tanto, si tiene algún tipo de subprocesos no daemon, necesita algunos otros medios (que los ganchos de apagado) para cerrar todos los subprocesos no daemon y liberar otros recursos. Si no hay otros subprocesos que no sean daemon, al regresar de main
se cerrará la JVM y se llamarán a los ganchos de apagado.
Por alguna razón, los ganchos de cierre parecen ser un mecanismo infravalorado y mal entendido, y la gente está reinventando la rueda con todo tipo de ataques personalizados patentados para abandonar sus programas. Yo recomendaría usar ganchos de apagado; todo está ahí en el Runtime estándar que usarás de todos modos.
System.exit(0)
termina la JVM. En ejemplos simples como este, es difícil percibir la diferencia. El parámetro se transfiere al sistema operativo y normalmente se utiliza para indicar una terminación anormal (por ejemplo, algún tipo de error fatal), por lo que si llama a Java desde un archivo por lotes o un script de shell, podrá obtener este valor y hacerse una idea si la aplicación fue exitosa
Sería un gran impacto si System.exit(0)
en una aplicación implementada en un servidor de aplicaciones (piénsalo antes de probarlo).