2010-06-09 10 views
9

Editar: Parece que mi prueba para determinar si la JVM original había salido era defectuosa para empezar (ver comentarios en la respuesta aceptada). Perdón por el ruido.Usando Java, ¿puedo hacer que una JVM genere otra, y luego hacer que la original salga?

Necesito tener una JVM en ejecución para iniciar otra JVM y luego salir. Actualmente estoy tratando de hacer esto a través del Runtime.getRuntime().exec(). La otra JVM se inicia, pero mi JVM original no saldrá hasta que se detenga el proceso de JVM "hijo". Parece que usar Runtime.getRuntime().exec() crea una relación padre-hijo entre los procesos. ¿Hay alguna forma de desvincular el proceso generado para que el padre pueda morir, o algún otro mecanismo para engendrar un proceso sin ninguna relación con el proceso de creación?

Tenga en cuenta que esto parece exactamente como esta pregunta: Using Java to spawn a process and keep it running after parent quits pero la respuesta aceptada no funciona, al menos no en mi sistema (Windows 7, Java 5 y 6). Parece que tal vez este es un comportamiento dependiente de la plataforma. Estoy buscando una plataforma independiente manera de invocar de manera confiable el otro proceso y dejar que mi proceso original muera.

Por ejemplo, supongamos que tengo un archivo jar en C:\myjar.jar y quiero ejecutar la clase com.example.RunMe que vive en ese contenedor. Digamos que la clase muestra un JOptionPane, y luego sale una vez que el usuario ha tocado OK.

Ahora, el siguiente es el programa que se ejecuta en la JVM # 1:

public static void main(String[] args) { 
    String javaHome = System.getProperty("java.home"); 
    String os = System.getProperty("os.name"); 
    String javawBin = javaHome + File.separator + "bin" + File.separator + "javaw"; 

    if (os.toLowerCase().contains("win")) { 
     javawBin += ".exe"; 
    } 

    List<String> cmd = new ArrayList<String>(); 

    cmd.add("\"" + javawBin + "\""); 
    cmd.add("-cp"); 
    cmd.add("\"C:\\myjar.jar\""); 
    cmd.add("com.example.RunMe"); 

    System.out.println("Running: " + cmd); 

    try { 

     System.out.println("Launching..."); 
     Process p = Runtime.getRuntime().exec(cmd.toArray(new String[cmd.size()])); 

     new Thread(new StreamGobbler(p.getInputStream())).start(); 
     new Thread(new StreamGobbler(p.getErrorStream())).start(); 

     System.out.println("Launched JVM."); 

     System.exit(0); 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

} 

private static class StreamGobbler implements Runnable { 
    InputStream stream; 

    StreamGobbler(InputStream stream) { 
     this.stream = stream; 
    } 

    public void run() { 
     byte[] buf = new byte[64]; 

     try { 
      while (stream.read(buf) != -1) 
       ; 
     } catch (IOException e) { 

     } 
    } 
} 

El comportamiento observado es que tanto "El lanzamiento de ..." y "Lanzado JVM." se imprimen, pero JVM n. ° 1 solo sale después de presionar Aceptar en JOptionPane lanzado por JVM n. ° 2. Además, el comportamiento es el mismo ya sea que inicie o no los hilos de los gobblers de la transmisión o no.

Además, para salvar a alguien la respiración, sí sé que podría crear un nuevo URLClassLoader con ese archivo jar y ejecutarlo de esa manera, pero eso no es lo que estoy tratando de hacer aquí.

+1

¿Puede proporcionar una muestra? – OscarRyz

Respuesta

4

Acabo de probar el siguiente código, y veo que los procesos se generan y el principal sale en Vista y Java 6. Creo que algo más podría estar pasando con su código.

public class Test { 
    public static void main(String[] args) throws Exception { 
     if(args.length == 0) 
      Runtime.getRuntime().exec("javaw Test loop"); 
     else 
      while(true){} 
    } 
} 
+0

Creo que tienes razón. Aquí está la cosa. Mi barómetro para verificar si JVM n. ° 1 ha salido es si el botón rojo "detener" estaba activo o no en la consola de Eclipse, ya que este ha sido un indicador confiable de la vida de JVM en el pasado. Sin embargo, el administrador de tareas de Windows me está mostrando una historia diferente, es decir, que la JVM n. ° 1 sale inmediatamente, como se esperaba. Entonces, ¿cómo se vincularía ese botón de parada del eclipse con el proceso secundario? – CarlG

+0

¿Tal vez Eclipse no entiende System.exit? – ykaganovich

+0

Todo lo que hace eclipse es engendrar javaw.exe. Tiene que haber algún tipo de vínculo al que se pueda agarrar? Sin embargo, es extraño que desaparezca del administrador de tareas. Tal vez he hecho una montaña de un grano de arena. – CarlG

0

Por lo que yo sé, matar un proceso con bastante frecuencia mata a todos los procesos secundarios. Dudo que haya una plataforma independiente para hacer esto.

+0

2 cosas: 1) ¿Puede un proceso engendrar otro proceso independiente que no es un niño? y 2) No puedo matar al padre en absoluto. System.exit (0) se bloquea hasta que se detiene el elemento secundario. – CarlG

0

Windows no establece el mismo tipo de relación padre-hijo entre procesos que los sistemas Unix. Es probable que su proceso principal no esté saliendo porque todavía hay un hilo ejecutándose en él. Este hilo puede estar esperando que finalice el proceso secundario, lo que podría explicar por qué su padre sale cuando sale el niño.

+0

El proceso principal se bloquea en System.exit (0). ¿No se adelantaría eso esperando que un hilo termine? Además, ¿esto sigue siendo cierto en Win7? – CarlG

+0

@CarlG: Colgar en 'System.exit (0)' es definitivamente inesperado.No me imagino que la semántica de la terminación del proceso haya cambiado en Windows 7, pero creo que podrían haberlo hecho. Tengo curiosidad por ver cuál es la resolución final para este. –

0

Sus hilos de ejecución StreamGobblers están dentro Proceso # 1, y no son hilos demonio, por lo que el proceso # 1 no termina hasta que esos hilos completos, cuando las corrientes que tragan desaparecen a medida que el proceso # 2 extremos.

Tome las dos líneas que crean esos hilos.

+0

Ese fue mi primer instinto, pero creo que System.exit (0) debería encargarse de ejecutar los hilos. Pero al leer la documentación de Runtime.exit, me pregunto si un código de error diferente daría lugar a un comportamiento diferente. – ykaganovich

+0

Razonable, pero como indiqué anteriormente, sacar esas 2 líneas no tiene ningún efecto. – CarlG

+0

Bien, lo siento. Llamar a 'System.exit (0) 'se encarga de esos hilos. –

Cuestiones relacionadas