博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java Process 阻塞测试总结
阅读量:6338 次
发布时间:2019-06-22

本文共 7952 字,大约阅读时间需要 26 分钟。

Process阻塞原因:输入流和错误流分开的,没有处理,就会发生阻塞,归根结底本质上是bio引起的io阻塞问题。

getInputStream,getErrorSteam就是获取脚本或者命令的控制台回显信息,前者获取的是标准输出的回显信息,后者获取的是标准错误的回显信息
Process原理:使用Runtime.getRuntime().exec(cmd)会在当前进程建立一个子进程,子进程由于没有控制台,它的标准输出和标准错误就会返回给父进程Process,因此通过getInputStream和getErrorStream就可以获取到这些信息。

测试代码如下:

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;public class JavaExeBat {        public JavaExeBat() {        }        public static void main(String[] args) {                Process p;                //test.bat中的命令是ipconfig/all                String cmd="sh test.sh ";                //String cmd="ping 127.0.0.1 -c 4";                try {                        //执行命令                        p = Runtime.getRuntime().exec(cmd);                        //取得命令结果的输出流                        //输出流                        InputStream fis=p.getInputStream();                        //错误流                        InputStream ferrs=p.getErrorStream();                        //用一个读输出流类去读                        InputStreamReader isr=new InputStreamReader(fis);                        InputStreamReader errsr=new InputStreamReader(ferrs);                        //用缓冲器读行                        BufferedReader br=new BufferedReader(isr);                        BufferedReader errbr=new BufferedReader(errsr);                        String line=null;                        String lineerr = null;                        //直到读完为止                        while((line=br.readLine())!=null) {                        //有可能发生阻塞的问题                                System.out.println("return input Str:" + line);                        }                        while((lineerr=errbr.readLine())!=null){                        //有可能发生阻塞的问题                                System.out.println("return err Str:" + lineerr);                        }                        int exitVal = p.waitFor();                        System.out.println("exitVal:" + exitVal);                } catch (Exception e) {                        e.printStackTrace();                }        }}复制代码

test.sh如下

#!/bin/bashfor((i=0; i < 100000; i++));do         //输出的标准输出        echo "testaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"        //输出到标准错误        echo "testaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 1>&2done复制代码

经过测试发现,如果JavaExeBat.java文件中只开启标准输出或者标准错误时,进程就会夯住,无法通过waiteFor获取其返回值,因为脚本中分别输出了100000w条信息到标准输出和标准错误,而下述代码只处理了getInputStream,导致标准错误输出流的信息太多返回给当前进程,没有得到处理,因此阻塞。代码如下:

p = Runtime.getRuntime().exec(cmd);                        //取得命令结果的输出流                        //输出流                        InputStream fis=p.getInputStream();                        //用一个读输出流类去读                        InputStreamReader isr=new InputStreamReader(fis);                        //用缓冲器读行                        BufferedReader br=new BufferedReader(isr);                        String line=null;                        //直到读完为止                        while((line=br.readLine())!=null) {                        //有可能发生阻塞的问题                                System.out.println("return input Str:" + line);                        }                        int exitVal = p.waitFor();                        System.out.println("exitVal:" + exitVal);复制代码

把上述代码中的getInputStream换做getErrorStream,也会夯住进程,因为同样只处理了两者中一者,即标准错误。

那么能不能同步处理两个流信息呢?代码如下:

try {                        //执行命令                        p = Runtime.getRuntime().exec(cmd);                        //取得命令结果的输出流                        //输出流                        InputStream fis=p.getInputStream();                        //错误流                        InputStream ferrs=p.getErrorStream();                        //用一个读输出流类去读                        InputStreamReader isr=new InputStreamReader(fis);                        InputStreamReader errsr=new InputStreamReader(ferrs);                        //用缓冲器读行                        BufferedReader br=new BufferedReader(isr);                        BufferedReader errbr=new BufferedReader(errsr);                        String line=null;                        String lineerr = null;                        //直到读完为止                        while((line=br.readLine())!=null) {                        //有可能发生阻塞的问题                                System.out.println("return input Str:" + line);                        }                        while((lineerr=errbr.readLine())!=null){                        //有可能发生阻塞的问题                                System.out.println("return err Str:" + lineerr);                        }                        int exitVal = p.waitFor();                        System.out.println("exitVal:" + exitVal);                } catch (Exception e) {                        e.printStackTrace();                }        }复制代码

测试过后发现也不行,因为是同步的,就会有先后顺序,也会发生阻塞,测试方法,将test.sh改为只打印标准错误,就会发现标准错误处理被阻塞,脚本如下:

#!/bin/bashfor((i=0; i < 100000; i++));do        //输出到标准错误        echo "testaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 1>&2done复制代码

解决办法思路:

  • (1)并发处理两个流信息,开启两个线程分别处理输出流与错误流
  • (2)将两个流合并为一个流 解决示例:
  • 第一种思路:
class ProcessExecutor      {          private Process p;          private List
outputList; private List
errorOutputList; public ProcessExecutor(Process p) throws IOException { if(null == p) { throw new IOException("the provided Process is null"); } this. p = p; } public List
getOutputList() { return this. outputList; } public List
getErrorOutputList() { return this.errorOutputList; } public int execute() { int rs = 0; Thread outputThread = new ProcessOutputThread(this.p.getInputStream()); Thread errorOutputThread = new ProcessOutputThread(this.p.getErrorStream()); outputThread.start(); errorOutputThread.start(); rs = p.waitFor(); outputThread.join(); errorOutputThread.join(); this.outputList = outputThread.getOutputList(); this.errorOutputList = errorOutputThread.getOutputList(); return rs; } } class ProcessOutputThread extends Thread { private InputStream is; private List
outputList; public ProcessOutputThread(InputStream is) throws IOException { if(null == is) { throw new IOException("the provided InputStream is null"); } this. is = is; this.outputList = new ArrayList
(); } public List
getOutputList() { return this. outputList; } @Override public void run() { InputStreamReader ir = null; BufferedReader br = null; try { ir = new InputStreamReader(this.is); br = new BufferedReader(ir); String output = null; while(null != (output = br.readLine())) { print(output); this.outputList.add(output); } } catch(IOException e) { e.print(); } finally ( try { if(null != br) { br.close(); } if(null != ir) { ir.close(); } if(null != this.is) { this.is.close(); } } catch(IOException e) { e.print(); } ) } } 复制代码
  • 第二种思路:使用ProcessBuilder,将其redirectErrorStream(true);将输出流与错误流合并
public int execute()      {          int rs = 0;          String[] cmds = {...};//command and arg            ProcessBuilder builder = new ProcessBuilder(cmds);            builder.redirectErrorStream(true);            Process process = builder.start();            BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));            String output = null;            while (null != (readLine = br.readLine()))          {                print(output);             }            rs = process.waitFor();          return rs;      }  复制代码

转载地址:http://coooa.baihongyu.com/

你可能感兴趣的文章
获取SQL数据库中的数据库名、所有表名、所有字段名、列描述
查看>>
Orchard 视频资料
查看>>
简述:预处理、编译、汇编、链接
查看>>
调试网页PAIP HTML的调试与分析工具
查看>>
路径工程OpenCV依赖文件路径自动添加方法
查看>>
玩转SSRS第七篇---报表订阅
查看>>
WinCE API
查看>>
SQL语言基础
查看>>
对事件处理的错误使用
查看>>
最大熵模型(二)朗格朗日函数
查看>>
html img Src base64 图片显示
查看>>
[Spring学习笔记 7 ] Spring中的数据库支持 RowMapper,JdbcDaoSupport 和 事务处理Transaction...
查看>>
FFMPEG中关于ts流的时长估计的实现(转)
查看>>
Java第三次作业
查看>>
【HDOJ 3652】B-number
查看>>
android代码混淆笔记
查看>>
Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) C. String Reconstruction 并查集
查看>>
BMP文件的读取与显示
查看>>
Flash文字效果
查看>>
各种排序算法总结篇(高速/堆/希尔/归并)
查看>>