Java:在线程中启动进程并获取对已创建进程的引用

时间:2016-11-09 13:34:51

标签: java process

我有以下集成测试代码,我可以在测试运行之前启动各种服务:

@BeforeClass
public static void setup() throws Exception {

  // Set some vars like javaBin location

  ProcessBuilder builder = new ProcessBuilder(javaBin, "-jar", "app.jar");
  Process process = launchProcess(builder);

}

private static Process launchProcess(ProcessBuilder builder) throws IOException {

  AtomicReference<Process> process = new AtomicReference<>();
  new Thread(() -> {
    try {
      process.set(builder.start());

      BufferedReader processStd =  new BufferedReader(new InputStreamReader(process.get().getInputStream());     
      BufferedReader processErr = new BufferedReader(new InputStreamReader(process.get().getErrorStream()));

      // To prevent deadlocks due to limited buffer size
      String s = "";
      while(processStd .readLine() != null) {}
      while((s = processErr .readLine()) != null) {
          System.err.println(s);
      }
    } 
    catch (IOException e) {
      e.printStackTrace();
    }
  }).start();

  return process.get();
}

该过程开始正常,但我process.get()始终返回null。我究竟做错了什么?如何使用上述方法获得对已启动流程的引用?如果我在setup()函数本身设置过程,即process = builder.start(),那么它可以正常工作。但是,它还会导致大量重复,因为我需要在单独的JVM中启动大量单独的服务。

1 个答案:

答案 0 :(得分:2)

问题很可能是在process.get()结尾处launchProcess返回时,线程实际上尚未启动。

在从方法返回之前,您需要等待线程实际启动并执行对process.set(builder.start())的调用。

这可以通过像CountDownLatch这样简单的事情来完成。

private static Process launchProcess(ProcessBuilder builder) throws IOException {
  final CountDownLatch latch = new CountDownLatch(1);
  // ...
  new Thread(() -> {
    try {
      process.set(builder.start());
      latch.countDown();
      //...
    } catch (IOException e) {
      //...
    }
  }).start();

  latch.await();
  return process.get();
}