如何为通过Runtime.getRuntime.exec()调用的Java程序传递输入
问题根因
- 第一,
runProcess.waitFor()的调用时机错误:你在给子进程传输入、读取子进程输出之前就等待子进程退出,此时子进程正阻塞等待输入,永远不会退出,直接形成死锁。 - 第二,存在多处未声明的变量:
pathJava、op都没有定义,代码本身无法编译通过。 - 第三,未处理子进程的错误流:子进程运行/编译时的错误输出会填满缓冲区,导致子进程主动阻塞。
- 第四,输入流关闭时机错误:刚写入一次输入就关闭输出流,无法支持多次输入场景,且写入后没有刷缓,数据可能停留在缓冲区没有传给子进程。
修正后代码
import java.io.*; import java.util.Scanner; public class Example { public static void main(String[] args) { try { // 修正变量名错误 String pathJava = "src/main/java/SampleProg.java"; compile(pathJava); Process runProcess = run(); // 获取子进程的输入流(我们给子进程写输入用这个)、输出流、错误流 BufferedWriter op = new BufferedWriter(new OutputStreamWriter(runProcess.getOutputStream())); BufferedReader processOut = new BufferedReader(new InputStreamReader(runProcess.getInputStream())); BufferedReader processErr = new BufferedReader(new InputStreamReader(runProcess.getErrorStream())); Scanner sc = new Scanner(System.in); // 单独开线程处理子进程的输出,避免阻塞 new Thread(() -> { try { String s; while ((s = processOut.readLine()) != null) { System.out.println("子进程输出:" + s); } } catch (IOException e) { e.printStackTrace(); } }).start(); // 单独开线程处理子进程的错误输出,避免缓冲区满阻塞 new Thread(() -> { try { String s; while ((s = processErr.readLine()) != null) { System.err.println("子进程错误:" + s); } } catch (IOException e) { e.printStackTrace(); } }).start(); // 主线程处理用户输入,传给子进程 while (sc.hasNextLine()) { String input = sc.nextLine(); op.write(input); op.newLine(); // 换行对应子进程readLine()的结束标记 op.flush(); // 强制刷缓,确保数据传给子进程 // 如果是结束输入的标记(比如输入exit就退出)可以在这里加判断关闭流 if ("exit".equalsIgnoreCase(input)) { op.close(); break; } } // 所有输入输出处理完再等待子进程退出 int exitCode = runProcess.waitFor(); System.out.println("子进程执行结束,退出码:" + exitCode); sc.close(); } catch (Exception e) { e.printStackTrace(); } } private static void compile(String pathJava) throws IOException, InterruptedException { String[] cmd = new String[4]; cmd[0] = "javac"; cmd[1] = "-d"; cmd[2] = "."; cmd[3] = pathJava; Process compileProcess = Runtime.getRuntime().exec(cmd); // 编译时也要处理输出和错误流,避免编译出错时阻塞 printStream(compileProcess.getInputStream(), System.out); printStream(compileProcess.getErrorStream(), System.err); int exitCode = compileProcess.waitFor(); if (exitCode != 0) { throw new RuntimeException("编译失败,退出码:" + exitCode); } } private static Process run() throws IOException { String[] cmd = new String[2]; cmd[0] = "java"; cmd[1] = "SampleProg"; return Runtime.getRuntime().exec(cmd); } // 工具方法:打印进程流内容 private static void printStream(InputStream in, PrintStream out) { new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { String line; while ((line = reader.readLine()) != null) { out.println(line); } } catch (IOException e) { e.printStackTrace(); } }).start(); } }
关键修改说明
- 调整
waitFor()的调用时机,等所有输入输出交互完成后再等待进程退出 - 新增单独线程处理子进程的标准输出、错误输出,避免缓冲区满导致的进程阻塞
- 补全所有缺失的变量声明和流初始化逻辑
- 输入写入后新增换行和刷缓操作,确保子进程可以正常识别输入结束
- 编译阶段新增错误判断和流处理,提前感知编译失败的问题
内容的提问来源于stack exchange,提问作者Aahlad Kethineedi
相关产品推荐
相关产品推荐

