java程序调用外部进程时不退出

1 遇到的问题: java启动一个外部程序,外部程序一直挂起不退出。

2 解决方法:启动两个线程, 分别读取外部程序的标准输出和标准错误输出。

3 参考代码:

String db3File = FileUtil.connectFile(workDirStr, fileName);
String cmd = "java -jar " + jarFile.getAbsolutePath() + " "
        + fileName;// + " debug" ; //db3 需要相对路径  可以添加debug参数查看生成文件
String expectZipFile = db3File+".4.zip";//期望的zip文件
logger.info("DB3生成zip包, cmd={}, 期望生成zip文件={}, workDir={}", cmd, expectZipFile, workDir);
Process process = Runtime.getRuntime().exec(cmd, null, workDir);

// 读取错误流和正常流的输入,否则会阻塞,不能正确获得结果
InputStream stderr = process.getErrorStream(); //获取标准错误输出流
getInputData(stderr, true);
InputStream inpbuildtar = process.getInputStream();//获取标准输出流
getInputData(inpbuildtar, false);

boolean isProcessFinsh = process.waitFor(20, TimeUnit.SECONDS);
if (!isProcessFinsh) {
    logger.info("DB3转换zip包, MapMaker.jar--失败, 程序20秒未执行完毕, workDir={}", workDirStr);
    return null;
}

/**
* 读流中数据
* 
* @param inputStream
*/
private static void getInputData(final InputStream inputStream, boolean isError) {
    //新开一个线程来读取创建的进程日志 必须这样 http://blog.csdn.net/mengxingyuanlove/article/details/50707746
    Thread thread = new Thread(new Runnable(){
        public void run(){
            logger.info("启动读取进程流, isError={}", isError);
            try {
                String msg = IOUtils.toString(inputStream, Charset.defaultCharset());


                if (isError) {
                    logger.error("DB3转换zip包, MapMaker.jar 返回={}", msg);
                } else {
                    logger.info("DB3转换zip包, MapMaker.jar 返回={}", msg);
                }
            } catch (IOException e) {
                logger.error("DB3转换zip包, MapMaker.jar Error, errorMsg=" + e.getMessage(), e);
            } finally {
                IOUtils.closeQuietly(inputStream);
            }
            logger.info("结束读取进程流, isError={}", isError);
        }
    });
    thread.start();
}

4 问题的分析

查看java.lang.Process.getInputStream()的帮助文档,有一句描述"Returns the input stream connected to the normal output of the subprocess."。方法返回的输入流是连接到子进程的输出流。 

java程序调用外部进程时不退出_第1张图片

如上图,子进程(就是你使用java启动的进程)向输出流写数据的时候,会放到缓冲区中,然后java进程通过对应的输入流读取。但是当缓冲区满了,子进程就会停住(现象就是子进程不退出)。

如果你的java程序不读取数据,当子进程输出少时,因为有缓存的存在,子进程不会阻塞。但是当子进程输出很多,缓冲区满了,就会阻塞了。

错误输出流同理。


你可能感兴趣的:(Java)