https://wiki.sei.cmu.edu/confluence/display/java/FIO07-J.+Do+not+let+external+processes+block+on+IO+buffers
java通过调用进程读取输出启动进程的标准输出时,如果被调用进程的,标准输出以及错误流的缓冲区被写满, 后续写入会导致调用进程会卡住,无法正常结束。
确保waiffor之前读取清空了所有流数据,并在waitfor 之后 关闭流。 在waifor 之前关闭仍有可能卡住!
These processes may require input to be sent to their input stream, and they may also produce output on their output stream, their error stream, or both. Incorrect handling of such external programs can cause unexpected exceptions, denial of service (DoS), and other security problems.
A process that tries to read input on an empty input stream will block until input is supplied. Consequently, input must be supplied when invoking such a process.
Output from an external process can exhaust the available buffer reserved for its output or error stream. When this occurs, the Java program can block the external process as well, preventing any forward progress for both the Java program and the external process. Note that many platforms limit the buffer size available for output streams. Consequently, when invoking an external process, if the process sends any data to its output stream, the output stream must be emptied. Similarly, if the process sends any data to its error stream, the error stream must also be emptied.
合格的代码(合并错误流, 并完全读取)
public class Exec {public static void main(String args[])throws IOException, InterruptedException {ProcessBuilder pb = new ProcessBuilder("notemaker");pb = pb.redirectErrorStream(true);Process proc = pb.start();InputStream is = proc.getInputStream();int c;while ((c = is.read()) != -1) {System.out.print((char) c);}int exitVal = proc.waitFor();} }
合格的代码2
class StreamGobbler implements Runnable {private final InputStream is;private final PrintStream os;StreamGobbler(InputStream is, PrintStream os) {this.is = is;this.os = os;}public void run() {try {int c;while ((c = is.read()) != -1)os.print((char) c);} catch (IOException x) {// Handle error }} }public class Exec {public static void main(String[] args)throws IOException, InterruptedException {Runtime rt = Runtime.getRuntime();Process proc = rt.exec("notemaker");// Any error message? Thread errorGobbler= new Thread(new StreamGobbler(proc.getErrorStream(), System.err));// Any output? Thread outputGobbler= new Thread(new StreamGobbler(proc.getInputStream(), System.out));errorGobbler.start();outputGobbler.start();// Any error?int exitVal = proc.waitFor();errorGobbler.join(); // Handle condition where theoutputGobbler.join(); // process ends before the threads finish } }