千家信息网

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

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要介绍了如何解决基于Process#waitFor()阻塞问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Process#
千家信息网最后更新 2026年11月03日如何解决基于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安全错误 数据库的锁怎样保障安全 互联网科技公司 互联网科技园 中关村互联网科技集团 互联网公司 科技公司 北京互联网科技公司 狮子座互联网科技 艾特科技互联网 苏州互联网科技贷款公司 友谊互联网络科技 多迪互联网科技有限公司 卓越科技互联网 招聘 深圳国际航运科技和互联网 晓花互联网科技有限公司网址 深圳市优智互联网科技有限公司 华夏恒生科技与互联网科技 滨湖区互联网智能科技产品有哪些 兰石爱特工业互联网科技分公司 同城互联网络科技 互联网科技品牌 长沙易易互联网科技有限公司 腾讯阿里互联网科技 广州善班互联网科技 银川新华互联网科技学校地址 安控科技rtu产品工业互联网 卫星互联网科技股票 互联网科技博主是什么意思 岳阳华臻互联网科技有限公司 乌鲁木齐新华智原互联网科技学校 洛阳共同富裕互联网科技有限公司 锡山区互联网智能科技产品供应
0