¿Cómo inicio un proceso completamente independiente desde un progtwig Java?

Estoy trabajando en un progtwig escrito en Java que, para algunas acciones , inicia progtwigs externos utilizando líneas de comando configuradas por el usuario. Actualmente utiliza Runtime.exec() y no conserva la referencia de Process (los progtwigs iniciados son un editor de texto o una utilidad de archivo, por lo que no es necesario que el sistema entre / elimine / err).

Sin embargo, hay un pequeño problema con esto, ya que cuando el progtwig Java se cierra, realmente no se cierra hasta que se salgan todos los progtwigs iniciados.

Lo preferiría mucho si los progtwigs lanzados fueran completamente independientes de la JVM que los lanzó.

El sistema operativo objective es múltiple, con Windows, Linux y Mac siendo el mínimo, pero cualquier sistema GUI con una JVM es realmente lo que se desea (de ahí la capacidad de configuración del usuario de las líneas de comando reales).

¿Alguien sabe cómo hacer que el progtwig lanzado se ejecute de forma completamente independiente de la JVM?


Editar en respuesta a un comentario

El código de lanzamiento es el siguiente. El código puede lanzar un editor ubicado en una línea y columna específica, o puede iniciar un visualizador de archivos. Los valores entrecomillados en la línea de comando configurada se tratan como ECMA-262 codificados, y se decodifican y se quitan las comillas para formar el parámetro exec deseado.

El lanzamiento ocurre en el EDT.

 static Throwable launch(String cmd, File fil, int lin, int col) throws Throwable { String frs[][]={ { "$FILE$" ,fil.getAbsolutePath().replace('\\','/') }, { "$LINE$" ,(lin>0 ? Integer.toString(lin) : "") }, { "$COLUMN$",(col>0 ? Integer.toString(col) : "") }, }; String[] arr; // array of parsed tokens (exec(cmd) does not handle quoted values) cmd=TextUtil.replace(cmd,frs,true,"$$","$"); arr=(String[])ArrayUtil.removeNulls(TextUtil.stringComponents(cmd,' ',-1,true,true,true)); for(int xa=0; xa<arr.length; xa++) { if(TextUtil.isQuoted(arr[xa],true)) { arr[xa]=TextDecode.ecma262(TextUtil.stripQuotes(arr[xa])); } } log.println("Launching: "+cmd); Runtime.getRuntime().exec(arr); return null; } 

Esto parece estar sucediendo solo cuando el progtwig se lanza desde mi IDE. Estoy cerrando esta pregunta ya que el problema existe solo en mi entorno de desarrollo; no es un problema en la producción . Desde el progtwig de prueba en una de las respuestas, y las pruebas adicionales que he llevado a cabo estoy satisfecho de que no es un problema que será visto por cualquier usuario del progtwig en cualquier plataforma.

Puede ser útil si publica una sección de prueba del código mínimo necesario para reproducir el problema. Probé el siguiente código en Windows y en un sistema Linux.

 public class Main { /** * @param args the command line arguments */ public static void main(String[] args) throws Exception { Runtime.getRuntime().exec(args[0]); } } 

Y probado con lo siguiente en Linux:

 java -jar JustForTesting.jar /home/monceaux/Desktop/__TMP/test.sh 

donde test.sh se ve así:

 #!/bin/bash ping -i 20 localhost 

así como esto en Linux:

 java -jar JustForTesting.jar gedit 

Y probado esto en Windows:

 java -jar JustForTesting.jar notepad.exe 

Todos ellos lanzaron sus progtwigs previstos, pero la aplicación Java no tuvo problemas para salir. Tengo las siguientes versiones de JVM de Sun según lo informado por java -version :

  • Windows: 1.6.0_13-b03
  • Linux: 1.6.0_10-b33

Todavía no he tenido la oportunidad de probar en mi Mac. Tal vez haya alguna interacción con otro código en su proyecto que pueda no estar clara. Es posible que desee probar esta aplicación de prueba y ver cuáles son los resultados.

Hay una relación padre-hijo entre sus procesos y usted tiene que romper eso. Para Windows puedes probar:

 Runtime.getRuntime().exec("cmd /c start editor.exe"); 

Para Linux, el proceso parece ejecutarse separado, de todos modos, no es necesario ningún nohup. Lo intenté con gvim , midori y acroread .

 import java.io.IOException; public class Exec { public static void main(String[] args) { try { Runtime.getRuntime().exec("/usr/bin/acroread"); } catch (IOException e) { e.printStackTrace(); } System.out.println("Finished"); } } 

Creo que no es posible hacerlo con Runtime.exec de una manera independiente de la plataforma.

para el sistema POSIX-Compatible:

  Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "your command"}).waitFor(); 

Aunque esta pregunta está cerrada, tengo algunas observaciones que pueden ayudar a otras personas que enfrentan un problema similar.

Cuando utiliza Runtime.getRuntime (). Exec () y luego ignora el manejador java.lang.Process que obtiene (como en el código del póster original), existe la posibilidad de que el proceso iniciado se bloquee.

Me he enfrentado a este problema en el entorno de Windows y he rastreado el problema a las streams stdout y stderr. Si la aplicación iniciada está escribiendo en estas secuencias, y el búfer para estas secuencias se llena, la aplicación lanzada puede parecer bloquearse cuando intenta escribir en las secuencias. Las soluciones son:

  1. Capture el identificador de proceso y vacíe las transmisiones continuamente, pero si desea finalizar la aplicación java inmediatamente después de iniciar el proceso, esta no es una solución viable.
  2. Ejecute la llamada al proceso como ‘cmd / c <>‘ (esto es solo para el entorno de Windows).
  3. Sufija el comando de proceso y redirija las streams stdout y stderr a nul usando ‘ command> nul 2> & 1

Desea iniciar el progtwig en segundo plano y separarlo del padre. Consideraría nohup (1) .

Sospecho que esto requeriría una horquilla de proceso real. Básicamente, el equivalente en C de lo que quiere es:

 pid_t id = fork(); if(id == 0) system(command_line); 

El problema es que no puedes hacer un fork () en Java puro. Lo que yo haría es:

 Thread t = new Thread(new Runnable() { public void run() { try { Runtime.getRuntime().exec(command); } catch(IOException e) { // Handle error. e.printStackTrace(); } } }); t.start(); 

De esta forma, la JVM aún no saldrá, pero no tendrá GUI y solo quedará una huella de memoria limitada.

Una forma en que puedo pensar es usar Runtime.addShutdownHook para registrar un hilo que elimine todos los procesos (por supuesto, necesitaría retener los objetos de proceso en alguna parte).

El gancho de cierre solo se invoca cuando sale la JVM, por lo que debería funcionar bien.

Un poco de hack pero efectivo.