Java Process 类
最后修改时间:2025 年 4 月 13 日
java.lang.Process
类提供了与系统进程交互的方法。它允许 Java 程序启动、控制和与原生操作系统进程进行通信。这对于系统级编程至关重要。
Process 对象由 Runtime.exec
或 ProcessBuilder.start
方法创建。它们代表在 Java 虚拟机外部运行的本机进程。该类提供了获取输入/输出流、等待完成和检查退出状态的方法。
Process 类方法
Process 类提供了多种用于进程管理的方法。这些方法包括用于 I/O 流访问、进程终止和状态检查的方法。该类是抽象类,平台特定的实现由 JVM 提供。
public abstract class Process { public abstract OutputStream getOutputStream(); public abstract InputStream getInputStream(); public abstract InputStream getErrorStream(); public abstract int waitFor() throws InterruptedException; public abstract int exitValue(); public abstract void destroy(); public Process destroyForcibly(); public boolean isAlive(); public boolean waitFor(long timeout, TimeUnit unit); }
上面的代码显示了 Process 类提供的主要方法。这些方法允许控制外部进程并通过标准流进行通信。现代 Java 版本添加了更多方法,以实现更好的进程控制。
基本进程执行
此示例演示如何执行简单的系统命令并等待其完成。我们使用 Runtime.getRuntime().exec
启动进程。waitFor
方法会阻塞,直到进程完成。
package com.zetcode; import java.io.IOException; public class Main { public static void main(String[] args) { try { // Execute a system command Process process = Runtime.getRuntime().exec("notepad.exe"); // Wait for the process to complete int exitCode = process.waitFor(); System.out.println("Process exited with code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
在本例中,我们启动 Windows 记事本并等待它关闭。waitFor
方法返回进程的退出代码。请注意,这是一个阻塞调用 - Java 程序将等待,直到记事本关闭。
读取进程输出
此示例演示如何读取进程的输出。我们执行一个产生输出的命令,并通过进程的输入流读取它。这对于捕获命令结果至关重要。
package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class Main { public static void main(String[] args) { try { // Execute a command that produces output Process process = Runtime.getRuntime().exec("cmd /c dir"); // Get the input stream of the process InputStream inputStream = process.getInputStream(); BufferedReader reader = new BufferedReader( new InputStreamReader(inputStream)); // Read the output line by line String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // Close resources reader.close(); process.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
在这里,我们执行 Windows dir
命令并读取其输出。进程的标准输出可通过 getInputStream
访问。我们将它包装在 BufferedReader 中,以便高效地逐行读取。完成后始终关闭流,以防止资源泄漏。
处理进程错误
此示例演示如何从进程读取错误输出。错误输出可通过 getErrorStream
获取的单独流获得。正确的错误处理对于健壮的进程管理至关重要。
package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class Main { public static void main(String[] args) { try { // Execute a command that might produce errors Process process = Runtime.getRuntime().exec("cmd /c dir nonexistent"); // Read standard output readStream(process.getInputStream(), "OUTPUT"); // Read error output readStream(process.getErrorStream(), "ERROR"); process.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } private static void readStream(InputStream inputStream, String type) throws IOException { BufferedReader reader = new BufferedReader( new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { System.out.println(type + ": " + line); } reader.close(); } }
在此示例中,我们尝试列出不存在的目录,这会生成错误输出。我们分别读取标准输出和错误流。错误流通常包含命令失败时的诊断消息。应始终读取两个流,以防止进程挂起。
写入进程输入
此示例演示如何将数据写入进程的输入流。某些程序接受通过其标准输入接收的输入。我们通过与 Python 解释器通信来演示这一点。
package com.zetcode; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; public class Main { public static void main(String[] args) { try { // Start Python interpreter Process process = Runtime.getRuntime().exec("python"); // Get the output stream to write to the process OutputStream outputStream = process.getOutputStream(); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(outputStream)); // Write Python commands to the process writer.write("print(2 + 3)\n"); writer.write("exit()\n"); writer.flush(); // Read the output readStream(process.getInputStream(), "PYTHON OUTPUT"); process.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } private static void readStream(java.io.InputStream inputStream, String type) throws IOException { java.io.BufferedReader reader = new java.io.BufferedReader( new java.io.InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { System.out.println(type + ": " + line); } reader.close(); } }
在这里,我们启动 Python 解释器并通过其标准输入向其发送命令。我们通过 getOutputStream
获取输出流,并将 Python 代码写入其中。写入后,我们必须刷新流以确保发送数据。然后从输入流读取 Python 输出。
ProcessBuilder 示例
此示例演示了用于进程创建的现代 ProcessBuilder
方法。ProcessBuilder 比 Runtime.exec() 提供对进程创建的更多控制。它允许设置环境变量和工作目录。
package com.zetcode; import java.io.IOException; import java.util.Arrays; public class Main { public static void main(String[] args) { try { // Create ProcessBuilder with command and arguments ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "echo", "Hello, ProcessBuilder!"); // Redirect error stream to standard output pb.redirectErrorStream(true); // Start the process Process process = pb.start(); // Read the combined output readStream(process.getInputStream(), "OUTPUT"); int exitCode = process.waitFor(); System.out.println("Exit code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } private static void readStream(java.io.InputStream inputStream, String type) throws IOException { java.io.BufferedReader reader = new java.io.BufferedReader( new java.io.InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { System.out.println(type + ": " + line); } reader.close(); } }
此示例使用 ProcessBuilder 执行带有参数的命令。我们设置 redirectErrorStream(true)
以将错误输出与标准输出合并。ProcessBuilder 比 Runtime.exec() 更受欢迎,因为它具有灵活性,并且可以更好地处理命令参数。它可以自动处理参数引用和拆分。
检查进程状态
此示例演示如何检查进程是否仍在运行并获取其退出值。isAlive
方法检查进程状态,而 exitValue
获取进程终止时的退出代码。
package com.zetcode; import java.io.IOException; public class Main { public static void main(String[] args) { try { // Start a long-running process Process process = Runtime.getRuntime().exec("ping -n 5 localhost"); // Check process status periodically for (int i = 0; i < 10; i++) { if (process.isAlive()) { System.out.println("Process is still running..."); } else { System.out.println("Process exited with code: " + process.exitValue()); break; } Thread.sleep(1000); } // If still running after 10 seconds, destroy it if (process.isAlive()) { System.out.println("Terminating process..."); process.destroy(); } } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
在这里,我们启动一个 ping 命令,该命令运行约 5 秒钟。我们使用 isAlive
定期检查其状态。如果进程在 10 秒后仍在运行,我们使用 destroy
终止它。请注意,如果在正在运行的进程上调用 exitValue
,则会引发异常。
销毁进程
此示例演示了终止进程的不同方法。destroy
方法请求正常终止,而 destroyForcibly
尝试在需要时强制终止。
package com.zetcode; import java.io.IOException; public class Main { public static void main(String[] args) { try { // Start a process that will run indefinitely Process process = Runtime.getRuntime().exec("notepad.exe"); System.out.println("Process started. Waiting 5 seconds..."); Thread.sleep(5000); // Try to destroy the process gracefully System.out.println("Attempting to destroy process..."); process.destroy(); // Wait a bit to see if it terminates Thread.sleep(1000); if (process.isAlive()) { System.out.println("Process still alive. Forcing termination..."); Process forced = process.destroyForcibly(); forced.waitFor(); System.out.println("Forced termination complete."); } else { System.out.println("Process terminated gracefully."); } } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
在本例中,我们启动记事本并尝试以编程方式关闭它。首先,我们尝试使用 destroy
进行正常终止。如果进程在一秒钟后仍然存活,我们使用 destroyForcibly
。destroyForcibly
方法返回一个 Process 对象,该对象可用于等待终止。这提供了对进程终止的更多控制。
来源
在本文中,我们通过实际示例介绍了 Java Process 类。进程管理对于系统集成和外部命令执行至关重要。Process 类为 Java 中的这些操作提供了基础。
作者
列出所有Java教程。