千家信息网

如何解决基于Process#waitFor()阻塞问题

发表于:2025-11-12 作者:千家信息网编辑
千家信息网最后更新 2025年11月12日,这篇文章主要介绍了如何解决基于Process#waitFor()阻塞问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Process#
千家信息网最后更新 2025年11月12日如何解决基于Process#waitFor()阻塞问题

这篇文章主要介绍了如何解决基于Process#waitFor()阻塞问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

Process#waitFor()阻塞问题

有时需要在程序中调用可执行程序或脚本命令:

Process process = Runtime.getRuntime().exec(shPath);int exitCode = process .waitFor();

Runtime.getRuntime()返回当前应用程序的Runtime对象,该对象的exec()方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。通过Process可以控制该子进程的执行或获取该子进程的信息。

它的所有标准io(即stdin,stdout,stderr)操作都将通过三个流(getOutputStream(),getInputStream(),getErrorStream())重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流出现失败,当缓冲区满之后将无法继续写入数据,则可能导致子进程阻塞,最终造成阻塞在waifor()这里。

针对这种情况,解法是要清空getInputStream()和getErrorStream()这两个流。而且两个流的清空一定是异步的。

static void drainInBackground(final InputStream is) {              new Thread(new Runnable(){                  public void run(){                      try{                          while( is.read() >= 0 );                      } catch(IOException e){                           // return on IOException                                      }                  }              }).start();          }

还有一种解法是用ProcessBuilder来创建Process对象,必须要使用ProcessBuilder的redirectErrorStream方法。redirectErrorStream方法设置为ture的时候,会将getInputStream(),getErrorStream()两个流合并,自动会清空流,无需自己处理。如果是false,getInputStream(),getErrorStream()两个流分开,就必须自己处理,程序如下:

try {              ProcessBuilder pbuilder=new ProcessBuilder("ping","192.168.0.125");              pbuilder.redirectErrorStream(true);              process=pbuilder.start();              reader=new BufferedReader(new InputStreamReader(process.getInputStream()));              String line=null;              while((line=reader.readLine())!=null){                  System.out.println(line);              }                 int result=process.waitFor();              System.out.println(result);          } catch (IOException e) {              // TODO Auto-generated catch block              e.printStackTrace();          } catch (InterruptedException e) {              // TODO Auto-generated catch block              e.printStackTrace();          }
Process process = null;            try {                process = launchProcess(cmdlist, environment);                StringBuilder sb = new StringBuilder();                String output = getOutput(process.getInputStream());                String errorOutput = getOutput(process.getErrorStream());                sb.append(output);                sb.append("\n");                sb.append(errorOutput);                boolean ret = process.waitFor(1L, TimeUnit.SECONDS);                if (!ret) {                    System.out.println(command + " is terminated abnormally. ret={}, str={}" + ret + " " + sb.toString());                }                return sb.toString();            } catch (Throwable e) {                System.out.println("Failed to run " + command + ", ");                e.printStackTrace();            } finally {                if (null != process) {                    process.destroy();                }            }            return "";

注意process一定要释放

Process.waitFor()导致主线程堵塞

今日开发的时候使用jdk自带的运行时变量 RunTime.getRunTime() 去执行bash命令。

因为该bash操作耗时比较长,所以使用了Process.waitFor()去等待子线程运行结束。

这个时候发现程序卡在waitFor()没有继续往下执行。

看了官方解释:

  • waitFor:等待子进程执行结束,或者已终止子进程,此方法立即返回。

当RunTime对象调用exec方法后,jvm会创建一个子进程,该子进程与jvm建立三个管道连接:标准输入流、标准输出流、标准错误流。假设该子进程不断向标准输入流、标准输出流写数据,而jvm不读取的话,会导致缓冲区塞满而无法继续写数据,最终堵塞在waitFor这里。

知道了问题所在就好处理了, 我们只需要将子进程返回的信息从缓冲区读取出来,便可以避免主线程堵塞问题。

public static void main(String[] args){    Process proc = RunTime.getRunTime().exec("sh /home/winnie/dataExtract.sh")     // 标准输入流(必须写在 waitFor 之前)    String inStr = consumeInputStream(proc.getInputStream());    // 标准错误流(必须写在 waitFor 之前)    String errStr = consumeInputStream(proc.getErrorStream());     int retCode = proc.waitFor();    if(retCode == 0){        System.out.println("程序正常执行结束");    }} /***   消费inputstream,并返回*/public static String consumeInputStream(InputStream is){    BufferedReader br = new BufferedReader(new InputStreamReader(is));    String s ;    StringBuilder sb = new StringBuilder();    while((s=br.readLine())!=null){        System.out.println(s);        sb.append(s);    }    return sb.toString();}

感谢你能够认真阅读完这篇文章,希望小编分享的"如何解决基于Process#waitFor()阻塞问题"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

进程 标准 程序 输入 问题 阻塞 对象 输出 两个 方法 篇文章 缓冲区 缓冲 数据 时候 线程 处理 三个 信息 命令 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 赛尔号服务器怎么选择 浦东新区技术软件开发销售电话 廊坊一触即发网络技术 机械手数控软件开发 公共安全与网络安全 软件开发 个人收汇 安徽潮流软件开发服务品质保障 《网络安全法》第三十一条 郑州广汇网络技术有限公司 辽宁网络安全讲座观后感 中国数据网络安全法施行时间 iba服务器怎么修改地址 浦东新区多功能软件开发 经营泛微软件开发 电脑服务器检查是否能上网 广东苹果软件开发价钱是多少 潜江网络安全维护公司哪家好 列举网络安全所涉及的学科名称 天津联想服务器维修系统云主机 服务器网络机柜比例 云时代的软件开发 java初级数据库面试题 华梦互联网科技有限公司 英雄联盟四川服务器 去日本做软件开发条件 2020年网络安全年度报告 推广软件开发报价含义 网络安全绘画图简单 人民 张家川网络安全宣传周 百度云服服务器安全组设置
0