我正在开发一个用Java编写的程序,对于某些操作,它使用用户配置的命令行启动外部程序。当前它使用Runtime.exec()并且不保留Process引用(启动的程序是文本编辑器或存档实用程序,因此不需要系统输入/输出/错误流)。
Runtime.exec()
Process
但是,这有一个小问题,即当Java程序退出时,直到所有启动的程序都退出后,它才真正退出。
如果启动的程序完全独立于启动它们的JVM,我将更喜欢它。
目标操作系统是多个,最低要求是Windows,Linux和Mac,但是真正需要的是带有JVM的任何GUI系统(因此用户可以配置实际的命令行)。
有谁知道如何使启动的程序完全独立于JVM执行?
编辑以回应评论
启动代码如下。该代码可以启动位于特定行和列的编辑器,也可以启动档案查看器。在配置的命令行中,将引号值视为ECMA-262编码,然后对其进行解码,并去除引号以形成所需的exec参数。
启动发生在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; }
仅当从我的IDE启动该程序时,这似乎才发生。由于问题仅存在于我的开发环境中,因此我将结束这个问题。在生产中这不是问题。根据测试程序的答案之一,以及我进行的进一步测试,我很满意,这个问题不会在任何平台上被该程序的任何用户看到。
如果你发布一个重现问题所需的最少代码的测试部分,则可能会有所帮助。我在Windows和Linux系统上测试了以下代码。
public class Main { /** * @param args the command line arguments */ public static void main(String[] args) throws Exception { Runtime.getRuntime().exec(args[0]); } }
并在Linux上进行了以下测试:
java -jar JustForTesting.jar /home/monceaux/Desktop/__TMP/test.sh
test.sh如下所示:
#!/bin/bash ping -i 20 localhost
在Linux上也是如此:
java -jar JustForTesting.jar gedit
并在Windows上对此进行了测试:
java -jar JustForTesting.jar notepad.exe
所有这些都启动了预期的程序,但是Java应用程序没有问题。我报告了以下版本的Sun JVM java -version:
我还没有机会在Mac上进行测试。可能与你项目中的其他代码发生了一些交互作用,可能还不清楚。你可能需要尝试此测试应用程序,然后查看结果。
你的流程之间存在父子关系,你必须打破这种关系。对于Windows,你可以尝试:
Runtime.getRuntime().exec("cmd /c start editor.exe");
对于Linux,该进程似乎仍然是独立运行的,不需要nohup。我试了一下gvim,midori和acroread。
gvim
midori
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"); } }