Java ProcessBuilder:结果进程挂起

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3285408/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 19:22:07  来源:igfitidea点击:

Java ProcessBuilder: Resultant Process Hangs

javalinuxcrashmultithreadingprocessbuilder

提问by Matt D

I've been trying to use Java's ProcessBuilder to launch an application in Linux that should run "long-term". The way this program runs is to launch a command (in this case, I am launching a media playback application), allow it to run, and check to ensure that it hasn't crashed. For instance, check to see if the PID is still active, and then relaunch the process, if it has died.

我一直在尝试使用 Java 的 ProcessBuilder 在 Linux 中启动一个应该“长期”运行的应用程序。这个程序运行的方式是启动一个命令(在这种情况下,我正在启动一个媒体播放应用程序),允许它运行,并检查以确保它没有崩溃。例如,检查 PID 是否仍处于活动状态,然后重新启动该进程(如果它已终止)。

The problem I'm getting right now is that the PID remains alive in the system, but the GUI for the application hangs. I tried shifting the ProcessBuilder(cmd).start() into a separate thread, but that doesn't seem to be solving anything, as I hoped it would have.

我现在遇到的问题是 PID 在系统中仍然有效,但应用程序的 GUI 挂起。我尝试将 ProcessBuilder(cmd).start() 转移到一个单独的线程中,但这似乎没有解决任何问题,正如我希望的那样。

Basically the result is that, to the user, the program APPEARS to have crashed, but killing the Java process that drives the ProcessBuilder.start() Process actually allows the created Process to resume its normal behavior. This means that something in the Java application is interfering with the spawned Process, but I have absolutely no idea what, at this point. (Hence why I tried separating it into another thread, which didn't seem to resolve anything)

基本上结果是,对于用户来说,程序似乎已经崩溃,但杀死驱动 ProcessBuilder.start() 进程的 Java 进程实际上允许创建的进程恢复其正常行为。这意味着 Java 应用程序中的某些内容正在干扰生成的进程,但此时我完全不知道是什么。(因此,为什么我尝试将它分成另一个线程,这似乎没有解决任何问题)

If anyone has any input/thoughts, please let me know, as I can't for the life of me think of how to solve this problem.

如果有人有任何意见/想法,请告诉我,因为我一生都无法想到如何解决这个问题。

Edit: I have no concern over the I/O stream created from the Process, and have thus taken no steps to deal with that--could this cause a hang in the Process itself?

编辑:我不关心从进程创建的 I/O 流,因此没有采取任何措施来处理 - 这会导致进程本身挂起吗?

采纳答案by nos

If the process writes to stderror stdout, and you're not reading it - it will just "hang" , blocking when writing to stdout/err. Either redirect stdout/errto /dev/nullusing a shell or merge stdout/errwith redirectErrorStream(true) and spawn another thread that reads from stdoutof the process

如果进程写入stderror stdout,而您没有读取它 - 它只会“挂起”,在写入时阻塞stdout/err。重定向stdout/err/dev/null使用 shell 或stdout/err与 redirectErrorStream(true)合并并产生另一个从stdout进程读取的线程

回答by Kaleb Pederson

Edit: I have no concern over the I/O stream created from the Process, and have thus taken no steps to deal with that--could this cause a hang in the Process itself?

编辑:我不关心从进程创建的 I/O 流,因此没有采取任何措施来处理 - 这会导致进程本身挂起吗?

If you don't read the output streams created by the process then it is possible that the application will block once the application's buffers are full. I've never seen this happen on Linux (although I'm not saying that it doesn't) but I have seen this exact problem on Windows. I think this is likely related.

如果您不读取进程创建的输出流,那么一旦应用程序的缓冲区已满,应用程序可能会阻塞。我从来没有在 Linux 上看到过这种情况(虽然我不是说它没有),但我在 Windows 上看到过这个确切的问题。我认为这可能是相关的。

回答by SyntaxT3rr0r

You want thetrick?

你想要把戏?

Don't start your process from ProcessBuilder.start(). Don't try to mess with stream redirection/consumption from Java (especially if you give no s**t about it ; )

不要从ProcessBuilder.start()开始您的流程。不要试图弄乱来自 Java 的流重定向/消耗(特别是如果你没有给出任何关于它的 s**t ;)

Use ProcessBuilder.start()to start a little shell script that gobbles all the input/output streams.

使用ProcessBuilder.start()启动一个小 shell 脚本,它吞噬所有输入/输出流。

Something like that:

类似的东西:

#!/bin/bash

nohup  >/dev/null 2>error.log &

That is: if you don't care about stdout and still want to log stderr (do you?) to a file (error.loghere).

也就是说:如果您不关心 stdout 并且仍然想将 stderr(是吗?)记录到一个文件(这里是error.log)。

If you don't even care about stderr, just redirect it to stdout:

如果您甚至不关心 stderr,只需将其重定向到 stdout:

#!/bin/bash

nohup  >/dev/null 2>1 &

And you call that tiny script from Java, giving it as an argument the name of the process you want to run.

然后你从 Java 中调用这个小脚本,将你想要运行的进程的名称作为参数提供给它。

If a process running on Linux that is redirecting both stdout and stderr to /dev/null still produce anythingthen you've got a broken, non-compliant, Linux install ;)

如果在 Linux 上运行的将 stdout 和 stderr 重定向到 /dev/null 的进程仍然产生任何结果,那么您的 Linux 安装已损坏、不合规;)

In other word: the above Just Works [TM] and get rid of the problematic "you need to consume the streams in this and that order bla bla bla Java-specific non-sense".

换句话说:上面的 Just Works [TM] 并摆脱了有问题的“你需要以这种和那种顺序消费流 bla bla bla Java-specific non-sense”

回答by Martin Buchholz

JDK7 will have builtin support for subprocess I/O redirection:

JDK7 将内置对子进程 I/O 重定向的支持:

http://download.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html

http://download.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html

In the meantime, if you really want to discard stdout/stderr, it seems best (on Linux) to invoke ProcessBuilder on a command that looks like:

同时,如果您真的想放弃 stdout/stderr,最好(在 Linux 上)在如下所示的命令上调用 ProcessBuilder:

["/bin/bash", "-c", "exec YOUR_COMMAND_HERE >/dev/null 2>&1"]

回答by user320781

Just stumbled on this after I had a similar issue. Agreeing with nos, you need to handle the output. I had something like this:

在我遇到类似问题后偶然发现了这一点。同意 nos,您需要处理输出。我有这样的事情:

ProcessBuilder myProc2 = new ProcessBuilder(command);
final Process process = myProc2.start();

and it was working great. The spawned process even did output someoutput but not much. When I started to output a lot more, it appeared my process wasn't even getting launched anymore. I updated to this:

它工作得很好。生成的进程甚至确实输出了一些输出,但输出不多。当我开始输出更多时,似乎我的进程甚至不再启动。我更新到这个:

ProcessBuilder myProc2 = new ProcessBuilder(command);
myProc2.redirectErrorStream(true);        
final Process process = myProc2.start();
InputStream myIS = process.getInputStream();
String tempOut = convertStreamToStr(myIS);

and it started working again. (Refer to this linkfor convertStreamToStr() code)

它又开始工作了。(convertStreamToStr() 代码参考此链接

回答by Hector

The thread running the process may block if it does not handle the output. This can be done by spawning a new thread that reads the output of the process.

如果不处理输出,运行该进程的线程可能会阻塞。这可以通过生成一个读取进程输出的新线程来完成。

    final ProcessBuilder builder = new ProcessBuilder("script")
                    .redirectErrorStream(true)
                    .directory(workDirectory);

    final Process process = builder.start();
    final StringWriter writer = new StringWriter();

    new Thread(new Runnable() {
        public void run() {
            IOUtils.copy(process.getInputStream(), writer);
        }
    }).start();

    final int exitValue = process.waitFor();
    final String processOutput = writer.toString();

回答by L.R.

In case you need to capture stdout and stderr and monitor the process then using Apache Commons Exechelped me a lot.

如果您需要捕获 stdout 和 stderr 并监视进程,那么使用Apache Commons Exec对我有很大帮助。

回答by Danilo Souza

I believe the problem is the buffering pipe from Linux itself.

我相信问题是来自 Linux 本身的缓冲管道。

Try to use stdbufwith your executable

尝试stdbuf与您的可执行文件一起使用

new ProcessBuilder().command("/usr/bin/stdbuf","-o0","*executable*","*arguments*");**

The -o0says not to buffer the output. The same goes to -i0and -e0if you want to unbuffer the input and error pipe.

-o0说不缓冲输出。同样去-i0-e0,如果你想无缓冲输入和错误管道。

回答by Beto Neto

Another solution is to start the process with Redirect.PIPEand close the InputStreamlike this:

另一种解决方案是启动Redirect.PIPE和关闭InputStream这样的过程:

ProcessBuilder builder = new ProcessBuilder(cmd);
builder.redirectOutput(Redirect.PIPE);
builder.redirectErrorStream(true); // redirect the SysErr to SysOut
Process proc = builder.start();
proc.getInputStream().close(); // this will close the pipe and the output will "flow"
procp.waitFor();

I tested this in Windows and Linux, and works!

我在 Windows 和 Linux 中对此进行了测试,并且有效!