[英]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?如何更正程序以及为什么它挂起?
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.