【问题标题】:Thread stops executing [duplicate]线程停止执行[重复]
【发布时间】:2016-06-28 07:56:04
【问题描述】:

我有一个在外部进程中运行 shell 脚本的线程,我正在使用 Apache 的 IOUtils 从这个外部进程中读取 stderr 和 stdout 流,如下所示:

Thread t = new Thread(()-> {
        ProcessBuilder pb =  new ProcessBuilder("sh");
        Process p = null;
        try {
            p = pb.start();
            OutputStream os = p.getOutputStream();
            os.write("sleep 30 ; echo test".getBytes());
            os.flush();
            os.close();
            InputStream is = p.getInputStream();
            InputStream es = p.getErrorStream();
            String stdout = IOUtils.toString(is,"UTF-8");
            String stderr = IOUtils.toString(es,"UTF-8");
            int retval = p.waitFor();
        } catch (Exception e) {
            System.out.println("Got exception: "+e.toString());
        } finally {
            System.out.println("Done now!");
        }
    });
t.start();
Thread.sleep(7000);
t.interrupt();

由于某种原因,当我运行这个测试用例时,从未抛出异常(catch 块永远不会运行),finally 块永远不会运行。有什么我没有解决的问题吗? stdout 和 stderr 是否应该由不同的线程收集?

【问题讨论】:

    标签: java multithreading io


    【解决方案1】:

    如果 stderr 的缓冲区已满,您的程序将停止。除非您需要它们位于不同的字符串中,否则我会将一个重定向到另一个。

    我会使用ProcessBuidler.redirectErrorStream 来组合输出,这样您就不需要额外的线程来读取标准错误

    waitFor(long, TimeUnit) 有超时,因此您无需启动后台线程。

    我建议您打印出您的 stderr 和 stdout,以便您查看它们,因为它们可能会指示出问题所在。

    【讨论】:

      【解决方案2】:

      看起来是正确的,除了线程在处理来自 shell 的任何输出之前被杀死(中断)。问题是shell休眠30秒,线程7秒中断。

      您没有看到来自 catch 或 finally 块的任何消息的事实可能是由于在“shell”线程实际激活之前从 main() 方法退出程序造成的。

      【讨论】: