首页 文章

Java ProcessBuilder:结果进程挂起

提问于
浏览
29

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

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

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

如果有人有任何意见/想法,请告诉我,因为我不能为我的生活想到如何解决这个问题 .

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

8 回答

  • 2

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

    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"]
    
  • 0

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

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

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

    -o0 表示不缓冲输出 . 如果要取消缓冲输入和错误管道, -i0-e0 也一样 .

  • 32

    如果进程写入stderr或stdout,并且你没有读它 - 它只会“挂起”,在写入stdout / err时会阻塞 . 使用shell将stdout / err重定向到/ dev / null或使用redirectErrorStream(true)合并stdout / err并生成从进程的stdout读取的另一个线程

  • 0

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

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

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

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

  • 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/

  • 2

    你想要的伎俩?

    不要从ProcessBuilder.start()启动您的进程 . 不要试图搞乱Java中的流重定向/消费(特别是如果你不给它任何关于它的话;)

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

    像这样的东西:

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

    那就是:如果你不关心stdout并且仍想将stderr(对吗?)记录到文件(error.log here) .

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

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

    你从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" .

相关问题