无法使用Apache Commons Exec为命令提供多个输入并提取输出

ftd*_*ube 8 java command-line multithreading inputstream apache-commons-exec

我正在编写一个Java应用程序,需要使用Apache Commons Exec库来使用外部命令行应用程序.我需要运行的应用程序具有相当长的加载时间,因此最好保持一个实例处于活动状态而不是每次都创建一个新进程.应用程序的工作方式非常简单.一旦启动,它会等待一些新输入并生成一些数据作为输出,这两个数据都使用应用程序的标准I/O.

因此,我们的想法是执行CommandLine,然后将PumpStreamHandler与三个独立的流(输出,错误和输入)一起使用,并使用这些流与应用程序进行交互.到目前为止,我已经在基本场景中完成了这项工作,我有一个输入,一个输出,然后应用程序关闭.但是一旦我试图进行第二次交易,就会出现问题.

在创建了我的CommandLine之后,我创建了我的Executor并像这样启动它:

this.executor = new DefaultExecutor();

PipedOutputStream stdout = new PipedOutputStream();
PipedOutputStream stderr = new PipedOutputStream();
PipedInputStream stdin = new PipedInputStream();
PumpStreamHandler streamHandler = new PumpStreamHandler(stdout, stderr, stdin);

this.executor.setStreamHandler(streamHandler);

this.processOutput = new BufferedInputStream(new PipedInputStream(stdout));
this.processError = new BufferedInputStream(new PipedInputStream(stderr));
this.processInput = new BufferedOutputStream(new PipedOutputStream(stdin));

this.resultHandler = new DefaultExecuteResultHandler();
this.executor.execute(cmdLine, resultHandler);
Run Code Online (Sandbox Code Playgroud)

然后我继续启动三个不同的线程,每个线程处理一个不同的流.我还有三个处理输入和输出的SynchronousQueues(一个用作输入流的输入,一个用于通知outputQueue已启动新命令而另一个用于输出).例如,输入流线程如下所示:

while (!killThreads) {
    String input = inputQueue.take();

    processInput.write(input.getBytes());
    processInput.flush();

    IOQueue.put(input);
}
Run Code Online (Sandbox Code Playgroud)

如果我删除while循环并执行一次,一切似乎都完美无缺.显然,如果我再次尝试执行它,PumpStreamHandler会抛出异常,因为它已被两个不同的线程访问.

这里的问题是,在线程结束之前,似乎没有真正刷新processInput.调试时,命令行应用程序仅在线程结束时才真正接收其输入,但如果保留while循环则永远不会获得它.我已经尝试了许多不同的东西来使processInput刷新,但似乎没有任何工作.

以前有人尝试过类似的东西吗?有什么我想念的吗?任何帮助将不胜感激!

ftd*_*ube 10

我最终找到了一种方法来完成这项工作.通过查看Commons Exec库的代码,我注意到PumpStreamHandler使用的StreamPumpers在每次有新数据传入时都没有刷新.这就是我执行一次代码时代码工作的原因,因为它会自动刷新并关闭流.所以我创建了一个名为AutoFlushingStreamPumper和AutoFlushingPumpStreamHandler的类.后者与普通的PumpStreamHandler相同,但使用AutoFlushingStreamPumpers而不是通常的.AutoFlushingStreamPumper与标准StreamPumper的作用相同,但每次向其写入内容时都会刷新其输出流.

我已经对它进行了相当广泛的测试,看起来效果很好.感谢所有试图解决这个问题的人!

  • 这非常有帮助,但正如@GroovyCakes所提到的,Gist会帮助更多 - 所以这是一个.注意这是我正在使用的,而不是OP所使用的.https://gist.github.com/4653381 (3认同)
  • 帮一个兄弟出去?我有同样的问题,你能不能给我一个"坚实的"并在这里发布你写的代码(AutoFlushingStreamPumper和AutoFlushingPumpStreamHandler)或者要点什么?重新发明那个轮子没有任何意义...感谢你的帖子! (2认同)