【问题标题】:Java Runtime.exec() asynchronous outputJava Runtime.exec() 异步输出
【发布时间】:2011-12-07 03:51:52
【问题描述】:

我想从一个长时间运行的 shell 命令中获取输出,因为它是可用的,而不是等待命令完成。我的代码在新线程中运行

Process proc = Runtime.getRuntime().exec("/opt/bin/longRunning");
InputStream in = proc.getInputStream();
int c;
while((c = in.read()) != -1) {
    MyStaticClass.stringBuilder.append(c);
}

问题是我在 /opt/bin/longRunning 中的程序必须在 InputStream 被分配和读取之前完成。有什么好的方法可以异步执行此操作吗?我的目标是 ajax 请求将返回当前值 MyStaticClass.stringBuilder.toString() 每秒左右。

我被困在 Java 5 上,仅供参考。

谢谢! W

【问题讨论】:

  • 谢谢大家! Apache Commons 的 Exec 是我的选择。 @Paul Cager,您还提供了一个绝妙的主意。被调用的脚本实际上是检测到它正在被管道和阻塞。但是,您从 Runtime.exec 获得的流是同步的,因此如果您尝试读取它,它就会阻塞。

标签: java ajax asynchronous struts runtime.exec


【解决方案1】:

Runtime.getRuntime().exec 确实 等待命令终止,因此您应该立即获得输出。也许输出正在被缓冲,因为命令知道它正在写入管道而不是终端?

【讨论】:

    【解决方案2】:

    试试Apache Common Exec。它能够异步执行一个进程,然后将输出“泵”到一个线程。查看Javadoc了解更多信息

    【讨论】:

      【解决方案3】:

      将阅读放在一个新线程中:

      new Thread() {
          public void run() {
              InputStream in = proc.getInputStream();
              int c;
              while((c = in.read()) != -1) {
                  MyStaticClass.stringBuilder.append(c);
              }
          }
      }.start();
      

      【讨论】:

      • 我在这里可能有点愚蠢,但是你如何将你的变量 c 从线程中取出?另外,c不应该是字符串吗?
      【解决方案4】:

      您是否编写了您正在调用的程序?如果是这样,请尝试在写入后刷新您的输出。文本可能卡在缓冲区中,无法进入您的 java 程序。

      我使用此代码来执行此操作,并且它有效:

          Runtime runtime = Runtime.getRuntime();
          Process proc = runtime.exec(command);
          BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
      
          while (true) {
      
              // enter a loop where we read what the program has to say and wait for it to finish
              // read all the program has to say
              while (br.ready()) {
                  String line = br.readLine();
                  System.out.println("CMD: " + line);
              }
      
              try {
                  int exitCode = proc.exitValue();
                  System.out.println("exit code: " + exitCode);
                  // if we get here then the process finished executing
                  break;
              } catch (IllegalThreadStateException ex) {
                  // ignore
              }
      
              // wait 200ms and try again
              Thread.sleep(200);
      
          }
      

      【讨论】:

      • BufferedReader.ready() 是否也覆盖了 BufferedReader.readLine() 的状态?文档只提到 ready() 表示何时可以使用 read() , readLine() 可能是几个 read() 操作,因此我理解这种方法可能仍然会阻塞。
      • 你是对的,它会阻塞并停留在这个循环中,直到子进程退出。这在我看来是正确的。如果您想在该程序完成运行之前执行其他操作,请将此代码放在单独的线程中,并在不同的线程中执行其他工作。我看不到一种方法可以使从 Process 返回的 InputStream 像使用网络套接字一样非阻塞。在这种情况下,当您尝试从流中读取时,它会引发超时异常。
      【解决方案5】:

      试试:

         try {  
               Process p = Runtime.getRuntime().exec("/opt/bin/longRunning");  
               BufferedReader in = new BufferedReader(  
                                          new InputStreamReader(p.getInputStream()));  
               String line = null;  
               while ((line = in.readLine()) != null) {  
               System.out.println(line);  }
      

      【讨论】:

        猜你喜欢
        • 2012-11-19
        • 2015-01-06
        • 2013-12-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-24
        • 1970-01-01
        • 2011-11-26
        相关资源
        最近更新 更多