如何从 Java 程序启动完全独立的进程?

2022-08-31 16:59:21

我正在开发一个用Java编写的程序,对于某些操作,它使用用户配置的命令行启动外部程序。目前,它使用并且不保留引用(启动的程序是文本编辑器或存档实用程序,因此不需要系统输入/输出/错误流)。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 启动程序时才会发生。我关闭了这个问题,因为问题只存在于我的开发环境中;这在生产中不是问题。从其中一个答案中的测试程序,以及我进行的进一步测试,我感到满意的是,在任何平台上,该程序的任何用户都不会看到这个问题。


答案 1

您的流程之间存在父子关系,您必须打破它。对于 Windows,您可以尝试:

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

对于Linux来说,这个过程似乎无论如何都是分离运行的,不需要nohup。我尝试了 , 和 。gvimmidoriacroread

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");
    }
}

我认为不可能以独立于平台的方式使用Running.exec

对于 POSIX 兼容系统:

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

答案 2

我有一些观察结果,可以帮助其他面临类似问题的人。

当您使用 Runtime.getRuntime().exec() 然后忽略您返回的 java.lang.Process 句柄(如原始海报中的代码)时,启动的进程可能会挂起。

我在Windows环境中遇到了这个问题,并将问题追溯到stdout和stderr流。如果启动的应用程序正在写入这些流,并且这些流的缓冲区已满,则当启动的应用程序尝试写入流时,它可能会显示为挂起。解决方案包括:

  1. 捕获进程句柄并不断清空流 - 但是如果您想在启动进程后立即终止java应用程序,那么这不是一个可行的解决方案
  2. 执行进程调用作为(这仅适用于 Windows 环境)。cmd /c <<process>>
  3. 为进程命令添加后缀,并使用“命令> nul 2>&1 将 stdout 和 stderr 流重定向到 nul'

推荐