2010-07-19 50 views
28

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

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

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

如果任何人有任何输入/想法,请让我知道,因为我不能为我的生活想到如何解决这个问题。

编辑:我不关心从流程创建的I/O流,因此没有采取任何措施来解决这个问题 - 这是否会导致流程本身挂起?

+3

既然你已经说过你没有处理流程的流程,我必须插话说“是的,这很可能是问题的原因。阅读是很重要的标准输出和标准错误的内容,并且如果孩子希望你写入标准输入“”。这将是值得您一阵子检查这个问题:http://stackoverflow.com/questions/882772/capturing-stdout-when-calling-runtime-exec/882795#882795 – 2010-07-19 22:07:50

回答

30

如果进程写入stderr或stdout,并且没有读取它 - 它只会“挂起”,写入stdout/err时会被阻塞。无论是使用shell将stdout /犯错到/ dev/null或与redirectErrorStream(真)合并标准输出/ ERR和产卵另一个线程从过程

+5

看起来非常重要!你必须从ffmpeg消费stdout/stderr。至少我注意到如此发布/消费rtmp连接。 – Nicholi 2012-08-30 18:09:16

2

编辑:我不关心从流程创建的I/O流,因此没有采取任何措施来解决这个问题 - 是否会导致流程本身挂起?

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

11

的读取标准输出你想要把戏?

不要从ProcessBuilder.start()开始您的过程。不要试图从Java的流重定向/消费混乱(尤其是如果你没有给它关于它;)

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

类似的东西:

#!/bin/bash 

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

那就是:如果你不关心stdout和仍想记录标准错误(你呢?)到一个文件中(error.log中这里)。

如果你甚至不关心标准错误,只需将其重定向到stdout:

#!/bin/bash 

nohup $1 >/dev/null 2>1 & 

你调用从Java脚本微小,给它作为一个参数要运行的进程的名称。

如果在Linux上运行的进程被重定向标准输出和标准错误到/ dev/null的仍然产生什么那么你已经有了破损,不符合一,Linux下安装;)

换句话说:上述Just Works [TM]并摆脱有问题的“你需要消耗这个流,并且该命令bla bla bla Java特定的无意义”

+0

得到了我们很好的笑声 - 现在是星期五晚上,这花费我们我们的晚上:) – 2017-03-24 20:13:06

5

在我遇到过类似的问题后,我偶然发现了这个问题。同意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/

11

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

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

线程似乎并没有结束 – user1120007 2015-01-29 09:38:15

0

如果您需要捕获输出和错误和监视然后用Apache Commons Exec帮了我不少的过程。

0

我认为问题在于Linux本身的缓冲管道。

尝试使用stdbuf与可执行

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

-o0说不要缓冲输出。 如果要解除输入和错误管道的缓冲区,请同样输入-i0-e0