使用ProcessBuilder实现非阻塞调用

需积分: 44 28 下载量 30 浏览量 更新于2023-03-16 收藏 28KB DOC 举报
"ProcessBuilder非阻塞是调用" 在Java编程中,`ProcessBuilder`类是用于创建操作系统子进程的工具。通常,当我们使用`Runtime.getRuntime().exec()`方法执行外部命令时,它会阻塞直到该命令执行完成。然而,通过使用`ProcessBuilder`,我们可以实现非阻塞调用,使得主线程不会等待子进程结束,从而提高程序的响应性和并发性。 `ProcessBuilder`非阻塞调用的关键在于正确地管理和读取子进程的输入、输出和错误流。在给定的代码片段中,我们看到了一个名为`StreamDrainer`的类,它的目的是消费子进程的输出流,以免它们阻塞进程的退出。以下是详细解释: 1. `StreamDrainer`类实现了`Runnable`接口,这意味着它可以通过`Thread`来执行。它的构造函数接受一个`InputStream`参数,这是子进程的输出或错误流。 2. 在`run()`方法中,`StreamDrainer`使用`BufferedReader`逐行读取输入流,每读取一行就将其打印到控制台。这样可以确保子进程的输出不会被缓冲并占用内存,同时避免阻塞。 3. 在`TestRunCmd`类的`main`方法中,我们看到创建了一个`ProcessBuilder`实例来执行外部命令(在这个例子中是Windows的`wmic process get name`命令,用于列出所有运行中的进程名称)。 4. `ProcessBuilder.start()`方法启动了子进程,并返回一个`Process`对象,这个对象提供了访问子进程的输入、输出和错误流的接口。 5. 创建了两个`StreamDrainer`线程,分别用于读取`Process`的`getInputStream()`(标准输出)和`getErrorStream()`(标准错误)。这两个线程在子进程启动后立即启动,这样即使子进程输出很多数据,也不会阻塞主线程。 6. `process.getOutputStream().close();`这行代码关闭了子进程的标准输入流,因为在本例中我们不需要向子进程发送任何输入。 7. `process.waitFor()`方法会阻塞当前线程,直到子进程结束。返回值是子进程的退出码,这在`System.out.println("返回值:"+exitValue);`中打印出来。 8. 如果在执行过程中出现异常,`e.printStackTrace();`将打印堆栈跟踪,帮助调试问题。 通过这种非阻塞的方式,主线程可以继续执行其他任务,而子进程的输出则由单独的线程处理。这种方法在处理长时间运行的外部命令或者需要并行执行多个任务时非常有用。