2010-09-15 26 views
154

En Java, ¿cuál es la diferencia con System.exit(0) o sin él en el código siguiente?¿Cuándo debemos llamar a System.exit en Java

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 no vuelve nunca normalmente." Qué significa eso?

Respuesta

170

System.exit() se puede utilizar para ejecutar shutdown hooks 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 al System.exit(), y los ganchos de apagado (si están configurados correctamente) se encargan de todas las ceremonias de cierre necesarias, como cerrar archivos, liberar recursos, etc.

"Este método nunca regresa normalmente." significa simplemente que el método no volverá; una vez que un hilo va allí, no volverá.

Otra forma, tal vez más común, de salir de 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 volver del 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; está todo allí en el estándar Runtime que usará de todos modos. Se necesita

+6

"Este método nunca vuelve normalmente". significa simplemente que el método no volverá; una vez que un hilo va allí, no volverá. Tenga en cuenta en particular que esto significa que no puede probar la unidad de un método que hace que una llamada System.exit (0) ... –

+5

-1 Incorrecto. Los ganchos de cierre se ejecutarán si la JVM finaliza normalmente, sin importar si es debido a System.exit o la terminación de main(). Ver http: //zx81/doku/java/javadoc/j2se1.5.0/docs/api/java/lang/Runtime.html#addShutdownHook%28java.lang.Thread%29 – sleske

+23

@sleske: La terminación de main() no es suficiente si hay otros hilos no-daemon alrededor. El apagado se inicia solo después de que finaliza el último subproceso no daemon, a menos que llame explícitamente a System.exit(). Eso está claramente establecido en la documentación de Runtime. –

44

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 no vuelve nunca Normalmente, esto significa que la línea posterior del código es efectivamente inalcanzable, a pesar de que el compilador no sabe que:

System.exit(0); 
System.out.println("This line will never be reached"); 

O se lanzará una excepción , o la VM terminará antes de regresar. Nunca "solo regresará".

Es muy raro que valga la pena llamar 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 .

+2

¿Por qué el compilador no lo sabe? ¿No es System.exit() lo suficientemente especial como para garantizar un código de detección específico? –

+3

@Bart: No, no lo creo. Poner casos especiales en el idioma para cosas como esta aumenta la complejidad del lenguaje con muy poco beneficio. –

+0

Pensé que "nunca regresa normalmente" tenía que ver con la "finalización abrupta" de la declaración. (JLS sección 14.1). ¿Me equivoco? – aioobe

5

System.exit

  • cuando se quiere devolver un código de error 0 no
  • cuando se quiere salir de su programa de algún lugar que no es el principal()

En su caso, hace exactamente lo mismo que el simple retorno-de-principal.

+0

¿Qué quieres decir con esto último?La forma correcta de cerrar el programa es detener todos los hilos (muy bien), un movimiento que no tiene que iniciarse desde el hilo principal, por lo que no es como 'salir' es su única opción allí. –

+0

@Bart: lo que describes es * una de las formas posibles * de cerrar un programa, no * de la manera correcta *. No hay nada de malo en utilizar los ganchos de apagado para detener todos los hilos de forma agradable. Y los ganchos de cierre se lanzan con 'exit'. No es la única opción, pero definitivamente es una opción que vale la pena considerar. –

+0

Pero lo que deduzco de los documentos, los ganchos de cierre son muy delicados y es posible que no tengan mucho tiempo para hacer lo que usted quiere que hagan. Por supuesto, utilícelos para salir bien en caso de que se cierre el sistema operativo o algo así, pero si va a llamar a System.exit() usted mismo, creo que es mejor hacer el código de apagado antes (después de lo cual probablemente no necesita System.exit() más) –

14

System.exit(0) finaliza 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 llamaras al System.exit(0) en una aplicación implementada en un servidor de aplicaciones (piénsalo antes de probarlo).

11

El método nunca regresa porque es el fin del mundo y ninguno de sus 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. usted tiene la opción de devolver un código personalizado para el medio ambiente, como, por ejemplo

System.exit(42); 

¿Quién va a hacer uso de su 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 la DO un código de salida y utilizarlo en una secuencia de comandos script o ventanas de UNIX cmd, se podría verificar this answer on this site

4

Java Language Specification dice que

Salir del Programa

Un programa finaliza toda su actividad y se cierra cuando ocurre una de dos cosas :

Todos los hilos que no están d hilos aemon terminan.

un poco de hilo invoca el método de salida de tiempo de ejecución de la clase o clases Sistema, y la operación de salida no está prohibido por el gerente de seguridad.

Significa que debe usarlo cuando tiene un programa grande (bueno, al menos más grande que este) y desea terminar su ejecución.

9

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. Llamar al System.exit iniciará los ganchos de cierre del programa y cualquier hilo que llame al System.exit se bloqueará hasta la finalización del programa. Esto tiene la consecuencia de que si el hook shutdown envía una tarea al hilo desde el que se llamó al System.exit, el programa se bloqueará.

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(); 
} 
+0

También tuve el problema donde System.exit en realidad no terminaría la JVM. Sin embargo, solo sucedió bajo ciertas condiciones. Una secuencia de comandos que tomé no me dio ninguna información sobre qué hilos/controladores de cierre están bloqueando el cierre. ¡Utilizar el código descrito en el comentario me ayudó a resolverlo! – Kai

3

Si tiene otro programa que se ejecuta en la JVM y utiliza System.exit, que el segundo programa se cerrará, también. 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, cerrar ganchos: Java shutdown hook, valor de retorno distinto de cero para llamadas de línea de comando: How to get the exit status of a Java program in Windows batch file).

también echar un vistazo a las excepciones de tiempo de ejecución: System.exit(num) or throw a RuntimeException from main?

4

uno nunca debe llamar System.exit (0).

  1. 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.
  2. 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.
  3. Oculta problemas de programación como ejecutar subprocesos que normalmente no se detienen.
  4. 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 0 tiene sentido si desea indicar la terminación anormal del programa.

+2

"Deberías tener siempre el control total del estado del sistema". Eso simplemente no es posible en Java. Los marcos de IoC y los servidores de aplicaciones son solo dos formas muy populares y ampliamente utilizadas de dejar el control del estado del sistema. Y eso está totalmente bien. – mhlz

+0

Ejecute System.exit (0) en su servidor de aplicaciones y cuénteme acerca de las reacciones de su administrador del servidor ... Se perdió el tema de esta pregunta y mi respuesta. – oopexpert

+0

Quizás no fui lo suficientemente claro. Deberías tener siempre el control total del estado del sistema del que eres responsable. Sí, algunas responsabilidades se cambiaron a servidores de aplicaciones y IoC. Pero no estaba hablando de eso. – oopexpert

4

Aunque la respuesta fue muy útil, pero de alguna manera se olvidó de algunos detalles adicionales. Espero que a continuación le ayudará a entender el proceso de apagado en Java, además de la respuesta anterior:

  1. En una ordenada * apagado, la JVM inicia por primera vez todos los ganchos de cierre registrados. Los ganchos de cierre son hilos no iniciados que están registrados con Runtime.addShutdownHook.
  2. JVM no ofrece garantías en el orden en que se inician los ganchos de cierre . Si alguno de los subprocesos de la aplicación (daemon o no demonio) aún se ejecuta en el momento del apagado, continúan ejecutándose al mismo tiempo que el proceso de cierre.
  3. Cuando se hayan completado todos los enganches de cierre, la JVM puede elegir ejecutar los finalizadores si runFinalizersOnExit es verdadero, y luego se detiene.
  4. JVM no intenta detener o interrumpir ningún subproceso de aplicación que aún se esté ejecutando en el momento del apagado; se terminan abruptamente cuando la JVM finalmente se detiene.
  5. Si los ganchos de cierre o los finalizadores no se completan, el proceso de apagado ordenado "se bloquea" y la JVM debe cerrarse abruptamente.
  6. 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.

PS: La JVM puede cerrar ya sea en una abrupta manera ordenada o .

  1. un cierre ordenado se inicia cuando la última (nondaemon) hilo “normal” termina, alguien llama System.exit, o por otros medios específicos de la plataforma (tal como enviar un SIGINT o golpear Ctrl-C).
  2. mientras que por encima es la forma estándar y preferido para la JVM se apague, sino que también puede ser cerrado bruscamente llamando Runtime.halt o matando el proceso JVM a través del sistema operativo (como el envío de un SIGKILL ) .
Cuestiones relacionadas