Guide to java.lang.Process API – java.lang.Process API指南

最后修改: 2018年 9月 15日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this tutorial, we’re going to take an in-depth look at the Process API.

在本教程中,我们将深入了解Process API

For a shallower look into how to use Process to execute a shell command, we can refer to our previous tutorial here.

关于如何使用Process来执行shell命令,我们可以参考之前的教程这里

The process that it refers to is an executing application. The Process class provides methods for interacting with these processes including extracting output, performing input, monitoring the lifecycle, checking the exit status, and destroying (killing) it.

它所指的进程是一个正在执行的应用程序。Process类提供了与这些进程交互的方法,包括提取输出、执行输入、监控生命周期、检查退出状态以及销毁(杀死)它。

2. Using Process Class for Compiling and Running Java Program

2.使用Process类来编译和运行Java程序

Let’s see an example to compile and run another Java program with the help of Process API:

让我们看一个例子,在Process API的帮助下,编译和运行另一个Java程序。

@Test
public void whenExecutedFromAnotherProgram_thenSourceProgramOutput3() throws IOException {
 
    Process process = Runtime.getRuntime()
      .exec("javac -cp src src\\main\\java\\com\\baeldung\\java9\\process\\OutputStreamExample.java");
    process = Runtime.getRuntime() 
      .exec("java -cp src/main/java com.baeldung.java9.process.OutputStreamExample");
    BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
    int value = Integer.parseInt(output.readLine());
 
    assertEquals(3, value);
}

Thus, the applications of executing Java code within an existing Java code is virtually limitless.

因此,在现有的Java代码中执行Java代码的应用几乎是无限的。

3. Creating Process

3.创造过程

Our Java application can call upon any application which is running within our computer system subjective to Operating System restrictions.

我们的Java应用程序可以调用在我们的计算机系统中运行的任何应用程序,但受操作系统限制。

Therefore we can execute applications. Let’s see what the different use cases we can run by utilizing the Process API are.

因此,我们可以执行应用程序。让我们看看通过利用Process API,我们可以运行哪些不同的用例。

The ProcessBuilder class allows us to create subprocesses within our application.

ProcessBuilder类允许我们在应用程序中创建子进程。

Let’s see a demo of opening Windows-based Notepad application:

让我们看看打开基于Windows的记事本应用程序的演示。

ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();

4. Destroying Process

4.摧毁过程

Process also provides us with methods to destroy sub-processes or process. Although, how the application is killed is platform-dependent.

Process还为我们提供了销毁子进程或进程的方法。尽管如此,应用程序如何被杀死是依赖于平台的

Let’s see different use cases by which are possible.

让我们看看不同的使用案例,这些案例都是可能的。

4.1. Destroying a Process by Reference

4.1.通过引用销毁一个进程

Let’s say we’re using Windows OS and want to spawn the Notepad application and destroy it.

假设我们使用的是Windows操作系统,想催生记事本程序并销毁它。

As before, we can create an instance of Notepad application by using the ProcessBuilder class and the start() method.

像以前一样,我们可以通过使用ProcessBuilder类和start()方法创建一个记事本应用程序的实例。

Then we can call the destroy() method on our Process object.

然后我们可以在我们的Process对象上调用destroy()方法。

4.2. Destroying a Process by ID

4.2.按ID销毁一个进程

We can also kill processes which are running within our Operating System that might not be created by our application.

我们也可以杀死在我们的操作系统中运行的、可能不是由我们的应用程序创建的进程。

Caution should be advised while doing this, as we can unknowingly destroy a critical process that might make the operating system unstable.

在这样做的时候应该注意,因为我们可能会在不知不觉中破坏一个关键的进程,可能会使操作系统不稳定

We first need to find out the process ID of the current running process by checking the task manager and find out the pid.

我们首先需要通过检查任务管理器找出当前运行进程的进程ID,并找出pid。

Let’s see an example:

让我们看一个例子。

long pid = /* PID to kill */;
Optional<ProcessHandle> optionalProcessHandle = ProcessHandle.of(pid);
optionalProcessHandle.ifPresent(processHandle -> processHandle.destroy());

4.3. Destroying a Process by Force

4.3.强行摧毁一个进程

On the execution of the destroy() method, the subprocess will get killed as we saw earlier in the article.

在执行destroy()方法时,子进程将被杀死,正如我们在文章前面看到的那样。

In the case when destroy() doesn’t work, we have the option of destroyForcibly().

destroy()不起作用的情况下,我们可以选择destroyForcibly().

We should always start with destroy() method first. After that, we can perform a quick check on the sub-process whether by executing isAlive().

我们应该总是先从destroy()方法开始。之后,我们可以通过执行isAlive()对子进程进行快速检查。

If it returns true then execute destroyForcibly():

如果它返回真,则执行destroyForcibly()

ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();
process.destroy();
if (process.isAlive()) {
    process.destroyForcibly();
}

5. Waiting for a Process to Complete

5.等待一个过程的完成

We also have two overloaded methods, through which we can ensure we can wait for completion of a process.

我们也有两个重载方法,通过这些方法,我们可以确保我们可以等待一个进程的完成。

5.1. waitfor()

5.1.waitfor()

When this method is executed, then it will place the current execution process thread in a blocking-wait state unless the sub-process gets terminated.

当这个方法被执行时,那么它将把当前执行进程线程置于阻塞等待状态,除非子进程被终止

Let’s take a look at the example:

让我们看一下这个例子。

ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();
assertThat(process.waitFor() >= 0);

We can see from the above example for the current thread to continue execution it will keep on waiting for the subprocess thread to end. Once the subprocess ends, the current thread will continue its execution.

从上面的例子中我们可以看到,为了让当前线程继续执行,它将一直等待子进程线程的结束。一旦子进程结束,当前线程将继续其执行。

5.2. waitfor(long timeOut, TimeUnit time)

5.2.waitfor(long timeOut, TimeUnit time)

When this method is executed, then it will place the current execution process thread in the blocking-wait state unless the sub-process gets terminated or runs out of time.

当这个方法被执行时,那么它将把当前执行进程线程置于阻塞等待状态,除非子进程被终止或耗尽时间

Let’s take a look at the example:

让我们看一下这个例子。

ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();
assertFalse(process.waitFor(1, TimeUnit.SECONDS));

We can see from the above example for the current thread to continue execution it will keep on waiting for the subprocess thread to end or if the specified time interval has elapsed.

从上面的例子中我们可以看到,当前线程要继续执行,它将继续等待子进程线程结束,或者如果指定的时间间隔已经过了。

When this method is executed, then it will return a boolean value of true if the subprocess has exited or a boolean value false if the wait time had elapsed before the subprocess exited.

当这个方法被执行时,如果子进程已经退出,那么它将返回一个布尔值true,如果在子进程退出之前等待时间已经过了,则返回一个布尔值false。

6. exitValue()

6.exitValue()

When this method is run then the current thread won’t wait for the sub-process to get terminated or destroyed, however, it will throw an IllegalThreadStateException if the subprocess isn’t terminated.

当这个方法被运行时,当前线程不会等待子进程被终止或销毁,然而,如果子进程没有被终止,它将抛出一个IllegalThreadStateException

Another way around if the subprocess has been successfully terminated then it will result in an exit value of the process.

另一种方法是,如果子进程已经成功终止,那么它将导致进程的退出值

It can be any possible positive integer number.

它可以是任何可能的正整数。

Let’s look at an example when the exitValue() method returns a positive integer when the subprocess has been terminated successfully:

让我们看一个例子,当子进程被成功终止时,exitValue()方法返回一个正整数。

@Test
public void 
  givenSubProcess_whenCurrentThreadWillNotWaitIndefinitelyforSubProcessToEnd_thenProcessExitValueReturnsGrt0() 
  throws IOException {
    ProcessBuilder builder = new ProcessBuilder("notepad.exe");
    Process process = builder.start();
    assertThat(process.exitValue() >= 0);
}

7. isAlive()

7.isAlive()

When we’d like to perform business processing which is subjective whether the process is alive or not.

当我们想进行业务处理时,而业务处理是主观的,无论这个过程是否活着。

We can perform a quick check to find whether the process is alive or not which returns a boolean value.

我们可以进行快速检查,以发现进程是否活着,这将返回一个布尔值。

Let’s see a quick example of it:

让我们来看看它的一个快速例子。

ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();
Thread.sleep(10000);
process.destroy();
assertTrue(process.isAlive());

8. Handling Process Streams

8.处理流程流

By default, the created subprocess does not have its terminal or console. All its standard I/O (i.e., stdin, stdout, stderr) operations will be sent to the parent process. Thereby the parent process can use these streams to feed input to and get output from the subprocess.

默认情况下,创建的子进程没有其终端或控制台。它的所有标准I/O(即stdin、stdout、stderr)操作将被发送到父进程。因此,父进程可以使用这些流来向子进程输入和获得输出。

Consequently, this gives us a huge amount of flexibility as it gives us control over the input/output of our sub-process.

因此,这给了我们巨大的灵活性,因为它使我们能够控制子过程的输入/输出。

8.1. getErrorStream()

8.1.getErrorStream()

Interestingly we can fetch the errors generated from the subprocess and thereon perform business processing.

有趣的是,我们可以从子进程中获取产生的错误,并在此基础上进行业务处理。

After that, we can execute specific business processing checks based on our requirements.

之后,我们可以根据我们的要求执行具体的业务处理检查。

Let’s see an example:

让我们看一个例子。

@Test
public void givenSubProcess_whenEncounterError_thenErrorStreamNotNull() throws IOException {
    Process process = Runtime.getRuntime().exec(
      "javac -cp src src\\main\\java\\com\\baeldung\\java9\\process\\ProcessCompilationError.java");
    BufferedReader error = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    String errorString = error.readLine();
    assertNotNull(errorString);
}

8.2. getInputStream()

8.2.getInputStream()

We can also fetch the output generated by a subprocess and consume within the parent process thus allowing share information between the processes:

我们还可以获取子进程产生的输出,并在父进程中进行消费,从而实现进程间的信息共享。

@Test
public void givenSourceProgram_whenReadingInputStream_thenFirstLineEquals3() throws IOException {
    Process process = Runtime.getRuntime().exec(
      "javac -cp src src\\main\\java\\com\\baeldung\\java9\\process\\OutputStreamExample.java");
    process = Runtime.getRuntime()
      .exec("java -cp  src/main/java com.baeldung.java9.process.OutputStreamExample");
    BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
    int value = Integer.parseInt(output.readLine());
 
    assertEquals(3, value);
}

8.3. getOutputStream()

8.3.getOutputStream()

We can send input to a subprocess from a parent process:

我们可以从一个父进程向子进程发送输入。

Writer w = new OutputStreamWriter(process.getOutputStream(), "UTF-8");
w.write("send to child\n");

8.4. Filter Process Streams

8.4.过滤过程流

It’s a perfectly valid use-case to interact with selective running processes.

这是一个完全有效的用例,可以与有选择的运行进程进行互动。

Process provides us the facility to selectively filter running processes based on a certain predicate.

Process为我们提供了根据某个前提条件有选择地过滤正在运行的进程的功能。

After that we can perform business operations on this selective process set:

之后,我们可以在这个选择性的流程集上执行业务操作。

@Test
public void givenRunningProcesses_whenFilterOnProcessIdRange_thenGetSelectedProcessPid() {
    assertThat(((int) ProcessHandle.allProcesses()
      .filter(ph -> (ph.pid() > 10000 && ph.pid() < 50000))
      .count()) > 0);
}

9. Conclusion

9.结论

Process is a powerful class for Operating System level interaction. Triggering terminal commands as well as launching, monitoring and killing applications.

Process是一个强大的操作系统级交互类。触发终端命令,以及启动、监控和杀死应用程序。

For more reading on the Java 9 Process API, take a look at our article here.

有关 Java 9 Process API 的更多内容,请查看我们的文章这里

As always, you’ll find the sources over on Github.

像往常一样,你可以在Github上找到源代码