从Java执行多个进程:输出混合?

时间:2013-12-31 13:33:17

标签: java servlets runtime.exec

我有一个servlet,它在doGet()中创建一个新的Action对象,该对象使用exec()来运行外部进程。可能会同时向servlet发出多个请求,因此我可能会有几个Action对象,其中每个对象同时运行一个外部进程。偶尔当发生这种情况时,我发现一个进程的输出与其他进程的输出混淆。

每个Action创建一个唯一的临时目录,并以此作为当前目录运行该进程。然后,单独的线程将进程的输出流读入字符串缓冲区。 Action对象执行的代码看起来基本上是这样的:

Process proc = null;
ReaderThread stdout = null;
ReaderThread stderr = null;
StringBuffer buff = new StringBuffer();
int exit = -1;
try {
  //
  //  Run the process
  //
  proc = Runtime.getRuntime().exec(command,null,directory);
  //
  //  Read the output from the process
  //
  stdout = new ReaderThread(proc.getInputStream(),buff);
  stderr = new ReaderThread(proc.getErrorStream(),buff);
  stdout.start();
  stderr.start();
  //
  //  Get the exit code
  //
  exit = proc.waitFor();
  //
  //  Wait for all the output to be read
  //
  stdout.join();
  stderr.join();
}
catch (InterruptedException e) {
  if (proc != null) {
    proc.destroy();
  }
}
catch (Exception e) {
  buff.append(e.getClass() + ": " + e.getMessage());
  if (proc != null) {
    proc.destroy();
  }
}

因此每个请求使用一个单独的Action对象来运行一个进程,并且它有自己的StringBuffer" buff"该过程的输出由两个ReaderThreads累积。但我发现,当两个请求同时运行两个进程时,一个的输出有时会在运行另一个的线程的StringBuffer中结束,并且两个servlet请求中的一个将看到输出打算用于另一个。它的行为基本上就像Runtime.exec()提供了一个全局管道,所有进程的输出流都连接到该管道。

ReaderThread看起来像这样:

public class ReaderThread extends Thread {
  private BufferedReader reader;
  private StringBuffer buffer;

  public ReaderThread (InputStream stream, StringBuffer buffer) {
    this.reader = new BufferedReader(new InputStreamReader(stream));
    this.buffer = buffer;
  }

  @Override
  public void run () {
    try {
      String line;
      while ((line = reader.readLine()) != null) {
        synchronized (buffer) {
          buffer.append(line + "\n");
        }
      }
    }
    catch (IOException e) {
      synchronized (buffer) {
        buffer.append(e.getMessage() + "\n");
      }
    }
  }
}

有人可以建议我可以做些什么来解决这个问题吗?

2 个答案:

答案 0 :(得分:0)

使用ThreadLocal变量存储每个线程的输出。

When and how should I use a ThreadLocal variable?

答案 1 :(得分:0)

这是解释,部分是一个警示故事:

  • 输出被添加到XML节点中的ArrayList 访问它
  • 通过克隆原型创建XML节点
  • ArrayList在声明中初始化,而不是在initialise()中初始化 类的方法,所以每个实例最终都引用相同的方法 对象。

咄。

我生命中又过了两天!#/ p>

新年快乐......