Java ProcessBuilder:结果进程挂起

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

我现在得到的问题是,PID在系统中保持活动状态,但应用程序的GUI挂起。 我尝试将ProcessBuilder(cmd).start()转换为一个单独的线程,但似乎没有解决任何问题,正如我所希望的那样。

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

如果有人有任何意见或build议,请让我知道,因为我不能为了我的生活而想到如何解决这个问题。

编辑:我不关心从stream程创build的I / Ostream,因此没有采取任何措施来处理 – 这可能会导致stream程本身的挂起?

如果进程写入标准错误或标准输出,而你没有读取它 – 它只会“挂起”,写入标准输出/错误时阻塞。 要么使用shell将stdout / errredirect到/ dev / null,要么使用redirectErrorStream(true)合并stdout / err,并产生另一个从进程的stdout读取的线程

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

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

你想要诀窍?

不要从ProcessBuilder.start()开始你的进程。 不要试图去混淆来自Java的streamredirect/消费(特别是如果你没有给它提供任何信息;)

使用ProcessBuilder.start()来启动一个小的shell脚本,用来捕获所有的input/输出stream。

类似的东西:

 #!/bin/bash nohup $1 >/dev/null 2>error.log & 

那就是:如果你不关心标准输出而仍然想把stderr(你呢?)logging到一个文件( error.log这里)。

如果你不关心stderr,只需将其redirect到标准输出:

 #!/bin/bash nohup $1 >/dev/null 2>1 & 

你从Java调用这个小脚本,把它作为你想运行的进程的名字作为参数。

如果在Linux上运行的将stdout和stderrredirect到/ dev / null的进程仍然会产生任何问题,那么您将得到一个不兼容的Linux安装;)

换句话说:上面的Just Works [TM],摆脱了这个问题, “你需要消耗这个stream,并且这个顺序是bla bla bla Java特定的无意义的”

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

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

而且工作很好。 产卵的过程甚至输出了一些输出,但不是很多。 当我开始输出更多的东西时,看起来我的程序甚至不再被启动。 我更新到这个:

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

并开始工作了。 (请参阅此链接convertStreamToStr()代码: http : //singztechmusings.wordpress.com/2011/06/21/getting-started-with-javas-processbuilder-a-sample-utility-class-to-interact-with -linux-from-java-program / )

编辑:我不关心从stream程创build的I / Ostream,因此没有采取任何措施来处理 – 这可能会导致stream程本身的挂起?

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

JDK7将支持subprocessI / Oredirect:

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

与此同时,如果你真的想丢弃stdout / stderr,在Linux上调用ProcessBuilder似乎是最好的:

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

如果你需要捕获stdout和stderr并监控进程,那么使用Apache Commons Exec帮助我很多。

我相信问题是Linux本身的缓冲pipe道。

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

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

-o0表示不缓冲输出。 如果你想要缓冲input和错误pipe道,同样可以使用-i0-e0