java exec原理,Java exec方法,如何正确处理流

What is the proper way to produce and consume the streams (IO) of external process from Java? As far as I know, java end input streams (process output) should be consumed in threads parallel to producing the process input due the possibly limited buffer size.

But I'm not sure if I eventually need to synchronize with those consumer threads, or is it enough just to wait for process to exit with waitFor method, to be certain that all the process output is actually consumed? I.E is it possible, even if the process exits (closes it's output stream), there is still unread data in the java end of the stream? How does the waitFor actually even know when the process is done? For the process in question, EOF (closing the java end of it's input stream) signals it to exit.

My current solution to handle the streams is following

public class Application {

private static final StringBuffer output = new StringBuffer();

private static final StringBuffer errOutput = new StringBuffer();

private static final CountDownLatch latch = new CountDownLatch(2);

public static void main(String[] args) throws IOException, InterruptedException {

Process exec = Runtime.getRuntime().exec("/bin/cat");

OutputStream procIn = exec.getOutputStream();

InputStream procOut = exec.getInputStream();

InputStream procErrOut = exec.getErrorStream();

new Thread(new StreamConsumer(procOut, output)).start();

new Thread(new StreamConsumer(procErrOut, errOutput)).start();

PrintWriter printWriter = new PrintWriter(procIn);

printWriter.print("hello world");

printWriter.flush();

printWriter.close();

int ret = exec.waitFor();

latch.await();

System.out.println(output.toString());

System.out.println(errOutput.toString());

}

public static class StreamConsumer implements Runnable {

private InputStream input;

private StringBuffer output;

public StreamConsumer(InputStream input, StringBuffer output) {

this.input = input;

this.output = output;

}

@Override

public void run() {

BufferedReader reader = new BufferedReader(new InputStreamReader(input));

String line;

try {

while ((line = reader.readLine()) != null) {

output.append(line + System.lineSeparator());

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} finally {

try {

reader.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} finally {

latch.countDown();

}

}

}

}

}

Is it necessary to use the latch here, or does the waitFor implicate all the output is already consumed? Also, if the output doesn't end/contain new line, will the readLine miss the output, or still read all that is left? Does reading null mean process has closed it's end of the stream - is there any other scenario where null could be read?

What is the correct way to handle streams, could I do something better than in my example?

解决方案

waitFor signals that the process ended, but you cannot be sure the threads which collect strings from its stdout and stderr finished also, so using a latch is a step in the right direction, but not an optimal one.

Instead of waiting for the latch, you can wait for the threads directly:

Thread stdoutThread = new Thread(new StreamConsumer(procOut, output)).start();

Thread stderrThread = ...

...

int ret = exec.waitFor();

stdoutThread.join();

stderrThread.join();

BTW, storing lines in StringBuffers is useless work. Use ArrayList instead, put lines there without any conversion, and finally retrieve them in a loop.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值