我正在开发一个用Java编写的程序,对于某些操作,它使用用户配置的命令行启动外部程序.目前它使用Runtime.exec()
并且不保留Process
引用(启动的程序是文本编辑器或存档实用程序,因此不需要系统输入/输出/错误流).
但是这有一个小问题,因为当Java程序退出时,在退出所有启动的程序之前它并没有真正退出.
如果启动的程序完全独立于启动它们的JVM,我会更喜欢它.
目标操作系统是多个,Windows,Linux和Mac是最小的,但任何带有JVM的GUI系统都是最理想的(因此实际命令行的用户可配置性).
有谁知道如何让启动的程序完全独立于JVM执行?
编辑以回复评论
启动代码如下.代码可以启动位于特定行和列的编辑器,也可以启动存档查看器.配置的命令行中的引用值被视为ECMA-262编码,并被解码并且引号被剥离以形成所需的exec参数.
这次发射发生在美国东部时间.
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
只有从我的IDE启动程序时才会出现这种情况.我正在关闭这个问题,因为问题只存在于我的开发环境中; 这不是生产中的问题.从其中一个答案中的测试程序,以及我进行的进一步测试,我感到满意的是,任何平台上的程序的任何用户都不会看到这个问题.
1> Ludwig Weinz..:您的流程之间存在父子关系,您必须打破它.对于Windows,您可以尝试:
Runtime.getRuntime().exec("cmd /c start editor.exe");对于Linux来说,无论如何,这个过程似乎都是分离的,不需要nohup.我尝试过
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"); } }我认为以独立于平台的方式使用Runtime.exec是不可能的.
适用于POSIX兼容系统:
Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "your command"}).waitFor();
"cmd/c start"的想法非常棒,帮助了很多.谢谢.
2> 小智..:虽然这个问题已经结束,但我有一些观察可以帮助其他人面临类似的问题.
当你使用Runtime.getRuntime().exec()然后忽略你得到的java.lang.Process句柄时(比如原始海报的代码),启动的进程可能会挂起.
我在Windows环境中遇到过这个问题,并将问题追溯到stdout和stderr流.如果启动的应用程序正在写入这些流,并且这些流的缓冲区已填满,则启动的应用程序在尝试写入流时可能会挂起.解决方案是:
捕获Process句柄并不断清空流 - 但是如果你想在启动流程后立即终止java应用程序,那么这不是一个可行的解决方案
执行进程调用为'cmd/c <>'(这仅适用于Windows环境).
使用' command> nul 2>&1 ' 后缀进程命令并将stdout和stderr流重定向到nul
谢谢.在推出kryonet客户的情况下,完全适合我.可以使用ProcessBuilder的inheritIO方法实现选项1.它将所有流内容发送到父Java进程.因此无需使流程独立
我在编写自定义启动器时遇到问题,其中子进程(主要是铬和洋泾浜)在运行几个小时后冻结,但是一旦打孔器退出,它们立即解冻.用Google搜索并调试了一个星期,这是我找到的问题的最佳答案.如果这也是我的问题,我会给你100 k点的答案.
3> 小智..:如果您发布重现问题所需的最小代码的测试部分,这可能会有所帮助.我在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.shtest.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
:
Windows:1.6.0_13-b03
Linux:1.6.0_10-b33
我还没有机会在我的Mac上进行测试.也许与项目中的其他代码发生了一些可能不太清楚的交互.您可能想要尝试此测试应用程序并查看结果.
Monceaux:谢谢,顺便说一句,这个简单的测试让我更接近程序没有退出的精确条件 - 从中我意识到它是我的*IDE*启动器而不是Java没有退出.