通过 ProcessBuilder 运行 java.exe 导致应用程序挂起? [英] Run java.exe through ProcessBuilder leads to application hanging?

查看:29
本文介绍了通过 ProcessBuilder 运行 java.exe 导致应用程序挂起?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

    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 包装在 PrintStreamautoFlush在:

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");

因为 autoFlushPrintStream 中打开,每当 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆