zoukankan      html  css  js  c++  java
  • java调用第三方命令,process.waitfor()挂起(你不知道的坑)

    我们常在java中运行第三方程序,如sh、python,java提供一个Runtime.exec()方法,生成一个Process对象。今天在使用这个方法的时候,发现接口半天没有返回数据。查了一下,原来还有这样的一个坑。记录一下

    代码是网上的,见如下。

     public static String execCmd(String cmd, File dir) throws Exception {
            StringBuilder result = new StringBuilder();
    
            Process process = null;
            BufferedReader bufrIn = null;
            BufferedReader bufrError = null;
    
            try {
                // 执行命令, 返回一个子进程对象(命令在子进程中执行)
                process = Runtime.getRuntime().exec(cmd, null, dir);
    
                // 方法阻塞, 等待命令执行完成(成功会返回0)
                process.waitFor();
    
                // 获取命令执行结果, 有两个结果: 正常的输出 和 错误的输出(PS: 子进程的输出就是主进程的输入)
                bufrIn = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
                bufrError = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
    
                // 读取输出
                String line = null;
                while ((line = bufrIn.readLine()) != null) {
                    result.append(line).append('
    ');
                }
                while ((line = bufrError.readLine()) != null) {
                    result.append(line).append('
    ');
                }
        return result
    }

    执行后,一直没有输出。原因如下:

    1. 主进程中调用Runtime.exec会创建一个子进程,用于执行shell脚本。子进程创建后会和主进程分别独立运行。

    2. 因为主进程需要等待脚本执行完成,然后对脚本返回值或输出进行处理,所以这里主进程调用Process.waitfor等待子进程完成。

    3. 通过shell脚本可以看出:子进程执行过程就是不断的打印信息。主进程中可以通过Process.getInputStream和Process.getErrorStream获取并处理。

    4. 这时候子进程不断向主进程发生数据,而主进程调用Process.waitfor后已挂起。当前子进程和主进程之间的缓冲区塞满后,子进程不能继续写数据,然后也会挂起。

    5. 这样子进程等待主进程读取数据,主进程等待子进程结束,两个进程相互等待,最终导致死锁

    解决方案:

        开两个线程在waitfor()命令之前读出窗口的标准输出缓冲区和标准错误流的内容。

            new Thread() {
                @Override
                public void run() {
                    BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
                    String line = null;
    
                    try {
                        while ((line = in.readLine()) != null) {
                            log.info("datax执行的结果为: "+line);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
    
            new Thread(){
                @Override
                public void run()
                {
                    BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                    String line = null;
                    StringBuilder result=new StringBuilder();
                    try
                    {
                        while((line = err.readLine()) != null)
                        {
                            result.append(line);
                        }
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                    finally
                    {
                        try
                        {
                            err.close();
                        }
                        catch (IOException e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
  • 相关阅读:
    MySQL 操作命令梳理(5)-执行sql语句查询即mysql状态说明
    MySQL 主从同步(5)-同步延迟状态考量(seconds_behind_master和pt-heartbea)
    MySQL 操作命令梳理(4)-中文乱码问题
    WebAssembly 介绍
    Android MVP
    Android Data Binding(数据绑定)用户指南
    认知心理学告诉你什么才是高效学习
    Android O新特性和行为变更总结zz
    音视频不同步问题的原因和解决方案
    当程序员写不出代码了,该怎么办?
  • 原文地址:https://www.cnblogs.com/SunHuaJ/p/11065426.html
Copyright © 2011-2022 走看看