6

我正在使用 Java 的 ProcessBuilder 来启动一个子进程,这是另一个必须在单独的 JVM 中运行的 Java 程序。

我启动两个线程从进程中读取 stdout 和 stderr 流,这样如果流缓冲区已满,就不会挂起。对 Process.waitFor 的调用返回,但流并未终止。

我使用的代码看起来像(命令是字符串列表):

ProcessBuilder pb = new ProcessBuilder(command);

final Process p = pb.start();
final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
final ByteArrayOutputStream errStream = new ByteArrayOutputStream();

Thread outputThread = new Thread() {
    @Override
    public void run() {
        try {
            IOUtils.copy(p.getInputStream(), outStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    };
};
outputThread.start();

Thread errorThread = new Thread() {
    @Override
    public void run() {
        try {
            IOUtils.copy(p.getErrorStream(), errStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    };
};
errorThread.start();

int returncode = p.waitFor();
outputThread.join();
errorThread.join();

如果我运行其他东西,例如“java -version”或“dir”或其他东西,代码可以正常工作。我可以访问我尝试运行的 Java 代码,但我从未听说您应该在 System.out 上调用 close()。

4

2 回答 2

3

Apache commons exec 为您完成所有这些工作。做起来容易很多...

http://commons.apache.org/exec/

于 2011-09-27T04:01:47.443 回答
0

据我所知,必须自行关闭 Process 对象的所有标准流。不管之前是否使用过。这似乎与 G1 垃圾收集器(自 Java 7 afaik 以来的默认值)高度相关,它在未明确关闭时保持管道打开 - 即使在子进程终止时也是如此。

我不熟悉这里的内部结构,但我在回答我的问题时发布的代码在调用 GhostScript 和其他很多的 24/7 系统上运行良好。

关于 SO 的其他问题和答案表明您必须明确关闭 Process 的 std-streams:

于 2011-09-19T15:23:02.343 回答