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

Java: Starting a process in a thread and getting a reference to the created 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()总是returnsnull。我究竟做错了什么?如何使用上述方法获取对已启动流程的引用?如果我在 setup() 函数本身中设置进程,即 process = builder.start(),那么它可以正常工作。但是,这也导致了很多重复,因为我需要在单独的 JVM 中启动许多单独的服务。

问题很可能是线程在您 return 和 process.get()launchProcess 结束时实际上尚未启动。

您需要等待线程实际启动并执行对 process.set(builder.start()) 的调用,然后才能从您的方法中 returning。

这可以用像 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();
}