java使用Process调用exe程序及Process.waitFor()死锁问题解决
作者:小肥羊冲冲冲
前言
最近在开发android的同时也在开发java ,碰到了需要使用java 程序调用exe的需求,这里我使用的 process 来调用的。该篇文章 读完需要8+分钟,文章类型为 小白入门类型,此处主要记录,方便以后学习补充… 如有不正确的地方还望海涵 及 指出….
文章参考
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程序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!