通过 ProcessBuilder 运行 java.exe 导致应用程序挂起? [英] Run java.exe through ProcessBuilder leads to application hanging?
问题描述
我有以下代码:
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--真的
并挂起
如何更正程序以及为什么它挂起?
How to correct program and why does it hangs on?
当我尝试写作时
java -cp project_folder\target\classes package.ExternalProcess
当我向控制台写入内容并返回预期结果时,它会等待 cmd 等待
from cmd it waiting when I write something to the console and returns expected result
推荐答案
问题在于缓冲,特别是 Process.getOutputStream()
的缓冲.如果我添加:
The problem is buffering, in particular, buffering of Process.getOutputStream()
. If I add:
processOutputStream.flush();
之后:
IOUtils.write("1" + System.lineSeparator(), processOutputStream);
它按预期工作.IOUtils.write
写入 processOutputStream
,它只是将数据保存在父进程的缓冲区中,但数据实际上并未通过连接发送到子进程,所以子进程挂在 br.readLine()
中,等待永远不会到来的数据.flush()
调用将数据从父级缓冲区发送到可以读取的子级.
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. The flush()
call sends the data from the buffer in the parent to the child where it can be read.
(您可以在 javadocs 中看到 Process.getOutputStream()
它说:
(You can see in the javadocs for Process.getOutputStream()
it says:
实施注意事项:对返回的输出流进行缓冲是个好主意.
Implementation note: It is a good idea for the returned output stream to be buffered.
虽然这并没有特别说标准实现是缓冲的,但可以合理地假设 Oracle 将遵循他们自己的实现建议.)
While that doesn't specifically say the standard implementation is buffered, it's reasonable to assume Oracle will follow their own implementation recommendations.)
如果您不想在每次写入后都调用 flush()
,您可以将 OutputStream
包装在 PrintStream
和 autoFlush
在:
If you don't want to have to call flush()
after every write, you can wrap the OutputStream
in a PrintStream
with autoFlush
on:
PrintStream processPrintStream = new PrintStream(processOutputStream, true);
然后不用IOUtils.write
,而是使用PrintStream
方法:
Then instead of using IOUtils.write
, just use the PrintStream
methods:
processPrintStream.println("1");
因为 autoFlush
在 PrintStream
中打开,每当 println
方法之一被调用(或写入字节数组或换行符),PrintStream
为您调用底层 OutputStream
上的 flush()
.
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.
这篇关于通过 ProcessBuilder 运行 java.exe 导致应用程序挂起?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!