java使用Process调用exe程序及Process.waitFor()死锁问题解决

 更新时间:2022年12月20日 09:05:42   作者:小肥羊冲冲冲  
在编写Java程序时,有时候我们需要调用其他的诸如exe,shell这样的程序或脚本,下面这篇文章主要给大家介绍了关于java使用Process调用exe程序及Process.waitFor()死锁问题解决的相关资料,需要的朋友可以参考下

前言

最近在开发android的同时也在开发java ,碰到了需要使用java 程序调用exe的需求,这里我使用的 process 来调用的。该篇文章 读完需要8+分钟,文章类型为 小白入门类型,此处主要记录,方便以后学习补充… 如有不正确的地方还望海涵 及 指出….

文章参考

process参考

waitfor挂起解析

1. 使用process调用exe程序

ProcessBuilder pb = new ProcessBuilder("C:\\Debug\\TestRedis.exe", keyNmae);
pb.redirectErrorStream(true);
Process process = pb.start();
//可能导致进程阻塞,甚至死锁
int ret = process.waitFor();
System.out.println("return value:"+ret);
System.out.println(process.exitValue());
byte[] bytes = new byte[process.getInputStream().available()];
process.getInputStream().read(bytes);
System.out.println(new String(bytes));
// ProcessBuilder api 方法
public ProcessBuilder(String... command) {
        this.command = new ArrayList<>(command.length);
        for (String arg : command)
            this.command.add(arg);
    }

首先我们先使用 processBuilder 创建出该对象,该对象我这里暂时使用了第一个参数为 exe 文件的地址,第二个参数为传递参数,是我需要传给exe 的字符串。后边主要就是打印 输入流,获取exe 输出信息。其实到这里java 调用exe 就已经完 了,但是后续开发中遇到一种问题,就是程序莫名死锁,没有响应,于是使用debug 跟进代码,发现程序走到 waitfor 代码行的时候程序就出现了挂起的情况,于是google了一番,明白了其中的原因。

2. waitfor 问题描述分析

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

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

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

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

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

3. 死锁问题解决

基于上述分析,只要主进程在waitfor之前,能不断处理缓冲区中的数据就可以。因为,我们可以再waitfor之前,单独启两个额外的线程,分别用于处理InputStream和ErrorStream就可以

try {
            //获取进程的标准输入流
            final InputStream is1 = process.getInputStream();
            //获取进城的错误流
            final InputStream is2 = process.getErrorStream();
            //启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
            new Thread() {
                public void run() {
                    BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));
                    try {
                        String line1 = null;
                        while ((line1 = br1.readLine()) != null) {
                            if (line1 != null){}
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    finally{
                        try {
                            is1.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();

            new Thread() {
                public void  run() {
                    BufferedReader br2 = new  BufferedReader(new  InputStreamReader(is2));
                    try {
                        String line2 = null ;
                        while ((line2 = br2.readLine()) !=  null ) {
                            if (line2 != null){}
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    finally{
                        try {
                            is2.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();

            //可能导致进程阻塞,甚至死锁
            int ret = process.waitFor();
            System.out.println("return value:"+ret);
            System.out.println(process.exitValue());
            logger.info("event:{}", "RunExeForWindows",process.exitValue());
            byte[] bytes = new byte[process.getInputStream().available()];
            process.getInputStream().read(bytes);
            System.out.println(new String(bytes));
            logger.info("event:{}", "RunExeForWindows",new String(bytes));
        }catch (Exception ex){
            ex.printStackTrace();
            try{
                process.getErrorStream().close();
                process.getInputStream().close();
                process.getOutputStream().close();
            }
            catch(Exception ee){}
        }

如此便可以将 waitfor死锁问题避开,看完这个问题,总结一下,多看官方api注释….其实官方已经提示我们,如下 为 api注释

Causes the current thread to wait, if necessary, until the
     * process represented by this {@code Process} object has
     * terminated.  This method returns immediately if the subprocess
     * has already terminated.  If the subprocess has not yet
     * terminated, the calling thread will be blocked until the
     * subprocess exits.
@return the exit value of the subprocess represented by this
     *         {@code Process} object.  By convention, the value
     *         {@code 0} indicates normal termination.
     * @throws InterruptedException if the current thread is
     *         {@linkplain Thread#interrupt() interrupted} by another
     *         thread while it is waiting, then the wait is ended and
     *         an {@link InterruptedException} is thrown.

如果需要,导致当前线程等待,直到此{@code Process}对象表示的进程具有终止 如果子进程,此方法立即返回已经终止。 如果子进程还没有终止后,调用线程将被阻塞,直到子进程退出。

总结

到此这篇关于java使用Process调用exe程序及Process.waitFor()死锁问题解决的文章就介绍到这了,更多相关java用Process调用exe程序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java发送post方法详解

    Java发送post方法详解

    这篇文章主要介绍了Java发送post方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • Spring MVC的web.xml配置详解

    Spring MVC的web.xml配置详解

    这篇文章主要介绍了Spring MVC的web.xml配置详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • java实现单机限流

    java实现单机限流

    这篇文章主要为大家详细介绍了java实现单机限流,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • springboot集成mybatisplus的方法

    springboot集成mybatisplus的方法

    这篇文章主要为大家详细介绍了springboot集成mybatisplus的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-04-04
  • Spring如何实现管理事务

    Spring如何实现管理事务

    Spring通过编程式事务和声明式事务管理来控制事务的边界和行为,声明式事务管理通过@Transactional注解实现,提供了丰富的配置选项来控制事务的行为,如传播行为、隔离级别、超时时间和回滚规则
    2024-11-11
  • Java NIO Path接口和Files类配合操作文件的实例

    Java NIO Path接口和Files类配合操作文件的实例

    下面小编就为大家分享一篇Java NIO Path接口和Files类配合操作文件的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-11-11
  • java控制台版实现五子棋游戏

    java控制台版实现五子棋游戏

    这篇文章主要为大家详细介绍了java控制台版实现五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • Sparsearray稀疏数组原理及实例详解

    Sparsearray稀疏数组原理及实例详解

    这篇文章主要介绍了Sparsearray稀疏数组原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • Java如何基于反射机制获取不同的类

    Java如何基于反射机制获取不同的类

    这篇文章主要介绍了Java如何基于反射机制获取不同的类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Java String 对象(你真的了解了吗)

    Java String 对象(你真的了解了吗)

    这篇文章主要介绍了Java String 对象(你真的了解了吗),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10

最新评论