【问题标题】:Java Process.waitFor() and IO streamsJava Process.waitFor() 和 IO 流
【发布时间】:2012-11-01 19:15:02
【问题描述】:

我有以下代码;

String[] cmd = { "bash", "-c", "~/path/to/script.sh" };
Process p = Runtime.getRuntime().exec(cmd);

PipeThread a = new PipeThread(p.getInputStream(), System.out);
PipeThread b = new PipeThread(p.getErrorStream(), System.err);

p.waitFor();

a.die();
b.die();

PipeThread 类非常简单,所以我将其全部包含在内;

public class PipeThread implements Runnable {

    private BufferedInputStream in;
    private BufferedOutputStream out;

    public Thread thread;

    private boolean die = false;

    public PipeThread(InputStream i, OutputStream o) {
        in = new BufferedInputStream(i);
        out = new BufferedOutputStream(o);
        thread = new Thread(this);
        thread.start();
    }

    public void die() { die = true; }

    public void run() {
        try {
            byte[] b = new byte[1024];
            while(!die) {
                int x = in.read(b, 0, 1024);
                if(x > 0) out.write(b, 0, x);
                else die();
                out.flush();
            }
        }
        catch(Exception e) { e.printStackTrace(); }

        try { 
            in.close();
            out.close();
        }
        catch(Exception e) { }
    }
}

我的问题是这样的; p.waitFor() 无休止地阻塞,即使在子进程终止后也是如此。如果我创建一对PipeThread 实例,那么p.waitFor() 可以完美运行。导致p.waitFor() 继续阻塞的 io 流的管道是什么?

我很困惑,因为我认为 IO 流是被动的,无法保持进程处于活动状态,或者让 Java 认为进程仍然处于活动状态。

【问题讨论】:

  • start()你的线程了吗?在您粘贴到此处的代码中,您没有。
  • @infgeoax start() 在构造函数中被调用。这可能是不好的做法,但它就在那里:)
  • 试试private volatile boolean die?
  • 哦,哇,我才意识到发生了什么……这很有趣,我会回答我自己的问题。希望有人会和我一起笑...
  • 当 read() 返回 -1 时,通常仅仅调用一个方法是不够的。您应该跳出循环并关闭流。在循环内使用 BufferedOutputStream 刷新也没什么意义。

标签: java runtime subprocess stdio


【解决方案1】:

在您的 PipeThread 代码中,您将永远循环直到 !die - 但您在 p.waitFor() 之后调用 PipeThread.die() - 究竟是什么阻止了 PipeThread 线程?

【讨论】:

  • PipeThread.run() 中,您将看到else die(); 行,它将在读取EOF 时终止线程(并关闭流)
  • 不要认为这是问题所在——但是 die 应该被声明为 volatile,因为它可以被多个线程访问。你确定线程正确终止(你能在 while 结束后立即放置一个 println)
  • 我已经检查了PipeThreads 的终止,它们工作正常。请参阅我的答案以了解造成混乱的原因。另外感谢volatile 的提示,我经常忘记它。
【解决方案2】:

因此,经过一番摸索,我意识到发生了什么事。 p.waitFor() 实际上并没有无限期地阻塞,而是我检查它的方法失败了;在p.waitFor() 之后的System.out.println() 语句。

PipeThread 是我在以前的项目中使用的一个类,我经常使用它在单独的线程中将一个流传输到另一个流。

这一定是我第一次使用System.outPipeThread 在读取 EOF 时关闭它传递的任何流。在这种情况下,两个流都包含我的标准输出,因此使用System.out.println 进行调试变得不可能...... :(

奇怪的是,IOException 没有被System.out.println() 抛出,我会调查的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多