background image

Java 调用外部程序线程 waitfor()堵塞情况解决

Java 调用外部程序的时候,发现线程会堵塞在 waitfor()方法。

  调用方法如下:

Process process = Runtime.getRuntime().exec(cmd);

process.waitfor();

   如果直接在 Shell 中调用这个程序,程序会很快结束,不会僵死。

  为什么会堵塞呢,原因是当调用 exec(cmd)后,JVM 会启动一个子进程,该进程会与

JVM 进程建立 3 个管道连接,标准输入,标准输出和标准错误流。假设该程序不断在向标

准输出流和标准错误流写数据,而 JVM 不读取,数据会暂时缓冲在 Linux 的缓冲区,缓

冲区满后该程序将无法继续写数据,会僵死,所以 Java 程序就会僵死在 waitfor(),永远

无法结束。

  解决办法就是增加两个线程,一个线程负责读标准输出流,另一个负责读标准错误

流,这样子数据就不会积压在缓冲区,程序就能够顺利运行。

  查看源代码后,还发现一个潜在的问题。但程序执行到 exec 的时候,JVM 会使用管

道,占有 3 个文件句柄,但程序运行结束后,这三个句柄并不会自动关闭,这样最终会

导致 java.io.IOException: Too many open files。所以就算外部程序的没有输出,也必须关闭

句柄:

Process process=null;

try{

  process = Runtime.getRuntime().exec(cmd);

  process.waitfor();

}cache{

  process.getOutputStream().close();

  process.getInputStream().close();

  process.getErrorStream().close();

}

   我们发觉当调用 close()方法后,JVM 并不会立即回收句柄,具体的回收时间不确定。

另外如果不调用 close(),

句柄也会被回收,也可能发生 Too many open files”的错误。根据这