process流阻塞分析

来源:互联网 发布:java中参数是什么意思 编辑:程序博客网 时间:2024/05/16 14:59

Java中

Runtime.getInstance().exec (String cmd)

或者

new ProcessBuilder(String cmd).start()

都可以产生子进程对象Process。通过调用Process对象的waitFor()方法可以使主进程进入等待状态,直至子进程执行完毕,再进行下一步工作。如果对子进程处理不当,有可能造成主进程阻塞,整个程序死掉。

java Api中关于Process说的是:

ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获取相关信息。Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。

创建进程的方法可能无法针对某些本机平台上的特定进程很好地工作,比如,本机窗口进程,守护进程,Microsoft Windows 上的 Win16/DOS 进程,或者 shell 脚本。创建的子进程没有自己的终端或控制台。它的所有标准 io(即 stdin,stdout,stderr)操作都将通过三个流 (getOutputStream()getInputStream()getErrorStream()) 重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。

在对getOutputStream()getInputStream()getErrorStream()的描述中,有个注意事项:对其输出流和错误流进行缓冲是一个好主意!嗯,好抽象啊!

问题正在于此,Process.getInputStream()和Process.getErrorStream()分别返回Process的标准输出流和错误流,两个流如果处理不当,其缓冲区不能被及时清除而被塞满,则进程被阻塞,即使调用Process.destory()也未必能销毁被阻塞的子进程。


如果尝试同步获取Process的输出流和错误流进行处理,未必有效,顺序执行过程中,输出流和错误流常常不能得到及时处理。解决方案有两个。


方案一:并发获取Process的输出流和错误流。

通过启动两个线程来并发地读取和处理输出流和错误流,懒得打开IDE了,就大概敲一下代码吧,可能有错误,如下:

调用者:

[java] view plaincopy
  1. class ProcessExecutor  
  2. {  
  3.     private Process p;  
  4.     private List<String> outputList;  
  5.     private List<String> errorOutputList;  
  6.     public ProcessExecutor(Process p) throws IOException  
  7.     {  
  8.         if(null == p)  
  9.         {  
  10.             throw new IOException("the provided Process is null");  
  11.         }  
  12.         this. p = p;  
  13.     }  
  14.     public List<String> getOutputList()  
  15.     {  
  16.         return this. outputList;  
  17.     }  
  18.     public List<String> getErrorOutputList()  
  19.     {  
  20.         return this.errorOutputList;  
  21.     }  
  22.     public int execute()  
  23.     {  
  24.         int rs = 0;  
  25.         Thread outputThread = new ProcessOutputThread(this.p.getInputStream());  
  26.         Thread errorOutputThread = new ProcessOutputThread(this.p.getErrorStream());  
  27.         outputThread.start();  
  28.         errorOutputThread.start();  
  29.         rs = p.waitFor();  
  30.         outputThread.join();  
  31.         errorOutputThread.join();  
  32.         this.outputList = outputThread.getOutputList();  
  33.         this.errorOutputList = errorOutputThread.getOutputList();  
  34.         return rs;  
  35.     }  
  36. }  


流处理线程

[java] view plaincopy
  1. class ProcessOutputThread extends Thread  
  2. {  
  3.     private InputStream is;  
  4.     private List<String> outputList;  
  5.     public ProcessOutputThread(InputStream is) throws IOException  
  6.     {  
  7.         if(null == is)  
  8.         {  
  9.             throw new IOException("the provided InputStream is null");  
  10.         }  
  11.         this. is = is;  
  12.         this.outputList = new ArrayList<String>();  
  13.     }  
  14.     public List<String> getOutputList()  
  15.     {  
  16.         return this. outputList;  
  17.     }  
  18.     @Override  
  19.     public void run()  
  20.     {  
  21.         InputStreamReader ir = null;  
  22.         BufferedReader br = null;  
  23.         try  
  24.         {  
  25.             ir = new InputStreamReader(this.is);  
  26.             br = new BufferedReader(ir);  
  27.             String output = null;  
  28.             while(null != (output = br.readLine()))  
  29.             {  
  30.                 print(output);  
  31.                 this.outputList.add(output);  
  32.             }  
  33.         }  
  34.         catch(IOException e)  
  35.         {  
  36.             e.print();  
  37.         }  
  38.         finally  
  39.         (  
  40.             try  
  41.             {  
  42.                 if(null != br)  
  43.                 {  
  44.                     br.close();  
  45.                 }  
  46.                 if(null != ir)  
  47.                 {  
  48.                     ir.close();  
  49.                 }  
  50.                 if(null != this.is)  
  51.                 {  
  52.                     this.is.close();  
  53.                 }  
  54.             }  
  55.             catch(IOException e)  
  56.             {  
  57.                 e.print();  
  58.             }  
  59.         )  
  60.     }  
  61. }  


方案二:用ProcessBuilder的redirectErrorStream()方法合并输出流和错误流。

[java] view plaincopy
  1. public int execute()  
  2. {  
  3.     int rs = 0;  
  4.     String[] cmds = {...};//command and arg    
  5.     ProcessBuilder builder = new ProcessBuilder(cmds);    
  6.     builder.redirectErrorStream(true);    
  7.     Process process = builder.start();    
  8.     BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));    
  9.     String output = null;    
  10.     while (null != (readLine = br.readLine()))  
  11.     {    
  12.         print(output);     
  13.     }    
  14.     rs = process.waitFor();  
  15.     return rs;  
  16. }   


http://blog.csdn.net/dancen/article/details/7969328
更多
http://www.cnblogs.com/nkxyf/archive/2012/12/13/2815978.html
0 0
原创粉丝点击