简体   繁体   English

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

[英]Run java.exe through ProcessBuilder leads to application hanging?

I have the following code:我有以下代码:

    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 source:外部进程源:

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

The first code produces第一个代码产生
--1-- true

and hangs on并坚持

How to correct program and why does it hangs on?如何更正程序以及为什么它挂起?

PS聚苯乙烯

When I just try to write当我尝试写作时

java -cp project_folder\target\classes package.ExternalProcess

from cmd it waiting when I write something to the console and returns expected result从 cmd 它等待我向控制台写入内容并返回预期结果

The problem is buffering, in particular, buffering of Process.getOutputStream() .问题是缓冲,特别是Process.getOutputStream()缓冲。 If I add:如果我添加:

processOutputStream.flush();

after:后:

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

it works as expected.它按预期工作。 IOUtils.write writes to processOutputStream , which just saves the data in a buffer in the parent process, but the data isn't actually sent across the connection to the child process, so the child process hangs in br.readLine() , waiting for data that's never coming. IOUtils.write写入processOutputStream ,它只是将数据保存在父进程的缓冲区中,但数据实际上并没有通过连接发送到子进程,因此子进程挂在br.readLine() ,等待永远不会到来的数据。 The flush() call sends the data from the buffer in the parent to the child where it can be read. flush()调用将数据从父级缓冲区发送到可以读取的子级。

(You can see in the javadocs for Process.getOutputStream() it says: (您可以在Process.getOutputStream()的 javadocs 中看到它说:

Implementation note: It is a good idea for the returned output stream to be buffered.实现说明:对返回的输出流进行缓冲是个好主意。

While that doesn't specifically say the standard implementation is buffered, it's reasonable to assume Oracle will follow their own implementation recommendations.)虽然这并没有特别说明标准实现是缓冲的,但假设 Oracle 将遵循他们自己的实现建议是合理的。)

If you don't want to have to call flush() after every write, you can wrap the OutputStream in a PrintStream with autoFlush on:如果您不想在每次写入后都调用flush() ,您可以将OutputStream包装在PrintStream并启用autoFlush

PrintStream processPrintStream = new PrintStream(processOutputStream, true);

Then instead of using IOUtils.write , just use the PrintStream methods:然后,而不是使用IOUtils.write ,只需使用PrintStream方法:

processPrintStream.println("1");

Because autoFlush is on in the PrintStream , whenever one of the println methods is called (or a byte array or newline is written), the PrintStream calls flush() on the underlying OutputStream for you.因为在PrintStream启用了autoFlush ,所以无论何时调用println方法之一(或写入字节数组或换行符), PrintStream为您调用底层OutputStream上的flush()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM