termino - temporizador en java con hilos
¿Cómo inicio un proceso completamente independiente desde un programa Java? (6)
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 corrientes 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:
- 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.
- Ejecute la llamada al proceso como ''cmd / c <>'' (esto es solo para el entorno de Windows).
- Sufija el comando de proceso y redirija las corrientes stdout y stderr a nul usando '' command> nul 2> & 1 ''
Estoy trabajando en un programa escrito en Java que, para algunas acciones , inicia programas externos utilizando líneas de comando configuradas por el usuario. Actualmente utiliza Runtime.exec()
y no conserva la referencia de Process
(los programas 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 programa Java se cierra, realmente no se cierra hasta que se salgan todos los programas iniciados.
Lo preferiría mucho si los programas lanzados fueran completamente independientes de la JVM que los lanzó.
El sistema operativo objetivo 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 programa 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 programa 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 programa 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 programa en cualquier plataforma.
Desea iniciar el programa en segundo plano y separarlo del padre. Consideraría nohup(1) .
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();
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 programas 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.
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.