我一直在尝试使用Java的ProcessBuilder在Linux中启动应该“长期”运行的应用程序 . 该程序运行的方式是启动命令(在这种情况下,我正在启动媒体播放应用程序),允许它运行,并检查以确保它没有崩溃 . 例如,检查PID是否仍处于活动状态,然后重新启动该进程(如果已经死亡) .
我现在遇到的问题是PID在系统中仍然存在,但应用程序的GUI挂起 . 我尝试将ProcessBuilder(cmd).start()转换为一个单独的线程,但这似乎并没有解决任何问题,正如我希望的那样 .
基本上结果是,对于用户来说,程序APPEARS已经崩溃,但是杀死了驱动ProcessBuilder.start()进程的Java进程实际上允许创建的进程恢复其正常行为 . 这意味着Java应用程序中的某些东西会干扰生成的进程,但此时我完全不知道是什么 . (因此为什么我尝试将它分成另一个线程,似乎没有解决任何问题)
如果有人有任何意见/想法,请告诉我,因为我不能为我的生活想到如何解决这个问题 .
编辑:我不关心从Process创建的I / O流,因此没有采取任何措施来处理 - 这是否会导致流程本身挂起?
8 回答
JDK7将内置支持子进程I / O重定向:
http://download.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html
与此同时,如果你真的想要丢弃stdout / stderr,最好(在Linux上)在一个看起来像这样的命令上调用ProcessBuilder:
我相信问题是来自Linux本身的缓冲管道 .
尝试将
stdbuf
与您的可执行文件一起使用-o0
表示不缓冲输出 . 如果要取消缓冲输入和错误管道,-i0
和-e0
也一样 .如果进程写入stderr或stdout,并且你没有读它 - 它只会“挂起”,在写入stdout / err时会阻塞 . 使用shell将stdout / err重定向到/ dev / null或使用redirectErrorStream(true)合并stdout / err并生成从进程的stdout读取的另一个线程
如果您没有读取进程创建的输出流,那么一旦应用程序的缓冲区已满,应用程序就可能会阻塞 . 我从来没有在Linux上看到过这种情况(虽然我并不是说它没有),但我在Windows上看到了这个确切的问题 . 我认为这可能是相关的 .
如果它不处理输出,则运行该进程的线程可能会阻塞 . 这可以通过生成一个读取进程输出的新线程来完成 .
如果你需要捕获stdout和stderr并监视进程,那么使用Apache Commons Exec对我帮助很大 .
在我遇到类似的问题之后,偶然发现了这一点 . 同意nos,您需要处理输出 . 我有这样的事情:
它工作得很好 . 产生的过程甚至输出了一些输出但不多 . 当我开始输出更多时,似乎我的过程甚至不再被启动了 . 我更新到这个:
它又开始工作了 . (请参阅此链接以获取convertStreamToStr()代码:http://singztechmusings.wordpress.com/2011/06/21/getting-started-with-javas-processbuilder-a-sample-utility-class-to-interact-with-linux-from-java-program/)
你想要的伎俩?
不要从ProcessBuilder.start()启动您的进程 . 不要试图搞乱Java中的流重定向/消费(特别是如果你不给它任何关于它的话;)
使用ProcessBuilder.start()启动一个吞噬所有输入/输出流的小shell脚本 .
像这样的东西:
那就是:如果你不关心stdout并且仍想将stderr(对吗?)记录到文件(error.log here) .
如果您甚至不关心stderr,只需将其重定向到stdout:
你从Java中调用那个小脚本,将它作为一个参数给你想要运行的进程的名称 .
如果在Linux上运行的将stdout和stderr重定向到/ dev / null的进程仍然产生任何东西,那么你就会遇到一个破坏的,不符合规范的Linux安装;)
换句话说:上面的Just Works [TM]并摆脱了有问题的"you need to consume the streams in this and that order bla bla bla Java-specific non-sense" .