通过ProcessBuilder运行java.exe导致应用程序挂起?

时间:2017-03-27 15:15:07

标签: java process stdout stdin processbuilder

我有以下代码:

    ProcessBuilder pb = new ProcessBuilder("C:\\Program Files\\Java\\jdk1.8.0_111\\bin\\java", "-cp", "project_folder\\target\\classes", "package.ExternalProcess"); 
    Process p = pb.start();
    OutputStream processOutputStream = p.getOutputStream();
    IOUtils.write("1" + System.lineSeparator(), processOutputStream);
    InputStream processInputStream = p.getInputStream();
    System.out.println("--1--");
    System.out.println(process.isAlive()); // outputs true
    String result = IOUtils.toString(processInputStream, "UTF-8"); //<-- hangs here
    System.out.println("--2--");
    p.waitFor();
    System.out.println(result);

ExternalProcess 来源:

public class ExternalProcess {
    public static void main(String[] args) {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String input = null;
        try {
            input = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("processed[" + input + "]");
    }
}

第一个代码生成
--1-- true

并挂起

如何更正程序以及为什么会挂起?

P.S。

当我试着写

java -cp project_folder\target\classes package.ExternalProcess

从cmd等待我向控制台写入内容并返回预期结果

1 个答案:

答案 0 :(得分:0)

问题在于缓冲,尤其是Process.getOutputStream()的缓冲。如果我添加:

processOutputStream.flush();

之后:

IOUtils.write("1" + System.lineSeparator(), processOutputStream);

它按预期工作。 IOUtils.write写入processOutputStream,它只是将数据保存在父进程的缓冲区中,但是实际上并没有通过与子进程的连接发送数据,因此子进程挂在{{ 1}},等待永远不会出现的数据。 br.readLine()调用将数据从父级缓冲区发送到子级,以便可以读取。

(您可以在java Process.getOutputStream()中看到它说:

实施说明:对返回的输出流进行缓冲是个好主意。

虽然没有特别说明说标准实现已被缓冲,但是可以合理地假设Oracle将遵循他们自己的实现建议。)

如果您不想在每次写入后都调用flush(),则可以将flush()包裹在OutputStream的{​​{3}}中:

autoFlush

然后不要使用PrintStream processPrintStream = new PrintStream(processOutputStream, true); ,而要使用IOUtils.write方法:

PrintStream

由于processPrintStream.println("1"); autoFlush中处于打开状态,因此每当调用PrintStream方法之一(或写入字节数组或换行符)时,println就会调用{ {1}}位于基础PrintStream上。