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

本文介绍了解决Java启动外部程序时出现的阻塞问题的方法。通过启动两个线程分别读取外部程序的标准输出和标准错误输出,避免了由于缓冲区满导致的程序挂起。文中还提供了具体的实现代码及分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.youkuaiyun.com/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启动的进程)向输出流写数据的时候,会放到缓冲区中,然后java进程通过对应的输入流读取。但是当缓冲区满了,子进程就会停住(现象就是子进程不退出)。

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

错误输出流同理。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值