Java Process详解

Process简介

我们在实际Java开发工作中可能会遇到调用操作系统命令的场景,比如查看下文件夹,执行下sh/exe文件等等,那么我们就要用到Process了!

首先,打开API来认识下Process :

Java代码 

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

 我们看到,Process是个抽象类,继承自“全民祖先”Object,有两种方式可以创建Process子类的实例,以及一系列进程交互方法:

Java代码 

  1. 方法摘要  
  2. abstract  void  destroy()   
  3.           杀掉子进程。  
  4. abstract  int   exitValue()   
  5.           返回子进程的出口值。  
  6. abstract  InputStream   getErrorStream()   
  7.           获取子进程的错误流。  
  8. abstract  InputStream   getInputStream()   
  9.           获取子进程的输入流。  
  10. abstract  OutputStream  getOutputStream()   
  11.           获取子进程的输出流。  
  12. abstract  int   waitFor()     此方法返回的退出值的过程。按照惯例,0表示正常终止。
  13.           导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。  

Process实战操练

学了那么多理论,还不如来个demo,我们来一个用“ping 百度网址”的例子吧,请看:

Java代码 

  1. import java.io.IOException;  
  2.   
  3. public class ProcessDemo {  
  4.     public static void main(String[] args) {  
  5.         try {  
  6.             Process process = Runtime.getRuntime().exec("ping www.baidu.com");  
  7.             System.out.println("任务执行完毕!");  
  8.         } catch (IOException e) {  
  9.             // TODO Auto-generated catch block  
  10.             e.printStackTrace();  
  11.         }  
  12.     }  
  13. }  

     

顺利运行,调用成功。但是结果是调用ping被挂到后台运行,程序直接打印了“任务执行完毕!”,而我们想要的效果是先把ping操作执行完成后,再输出“任务执行完毕!”。

好吧,Process提供了WaitFor和getInputStream两个方法,这两个方法都是阻塞java线程,等待脚本返回或结束后,再继续执行java程序,OK,那说改就改!

Java代码 

  1. import java.io.BufferedReader;  
  2. import java.io.IOException;  
  3. import java.io.InputStreamReader;  
  4.   
  5. public class ProcessDemo {  
  6.     public static void main(String[] args) {  
  7.         try {  
  8.             Process process = Runtime.getRuntime().exec("ping www.baidu.com");  
  9.             BufferedReader bufferedReader = new BufferedReader(  
  10.                     new InputStreamReader(process.getInputStream(),"gbk"));  
  11.             String line;  
  12.             while ((line = bufferedReader.readLine()) != null) {  
  13.                 System.out.println(line);  
  14.             }  
  15.             System.out.println("任务执行完毕!");  
  16.         } catch (IOException e) {  
  17.             // TODO Auto-generated catch block  
  18.             e.printStackTrace();  
  19.         }  
  20.     }  
  21. }  

Java代码 

  1. import java.io.IOException;  
  2.   
  3. public class ProcessDemo {  
  4.     public static void main(String[] args) {  
  5.         try {  
  6.             Process process = Runtime.getRuntime().exec("ping www.baidu.com");  
  7.             process.waitFor();  
  8.             System.out.println("任务执行完毕!");  
  9.         } catch (IOException e) {  
  10.             // TODO Auto-generated catch block  
  11.             e.printStackTrace();  
  12.         } catch (InterruptedException e) {  
  13.             // TODO Auto-generated catch block  
  14.             e.printStackTrace();  
  15.         }  
  16.     }  
  17. }  

这就是我们想要的啦~ 

问题进阶

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

       这句话晦涩难懂,但可以简单地归纳一下,针对可执行程序的输入输出每个平台都会提供缓冲区,当没有及时把缓冲数据读出,且可执行程序在短时间内有大量数据输入缓冲区的话,缓冲区撑满,进程就会被阻塞。

       好吧,那意思很清楚了,就是让我们在写Process程序的时候,尽量主动把可执行程序的输入和输出读出来,不要让它们长时间留在缓冲区。

       上代码,我们先创建一个线程类,它主要负责不停地来读出Process所调用脚本的输出数据(主要的是读出error信息):

Java代码 

  1. import java.io.BufferedReader;  
  2. import java.io.IOException;  
  3. import java.io.InputStream;  
  4. import java.io.InputStreamReader;  
  5.   
  6. public class CleanInputCache extends Thread {  
  7.     private InputStream is;  
  8.     private String type;  
  9.   
  10.     public CleanInputCache(InputStream is, String type) {  
  11.         this.is = is;  
  12.         this.type = type;  
  13.     }  
  14.   
  15.     public void run() {  
  16.         try {  
  17.             InputStreamReader isr = new InputStreamReader(is);  
  18.             BufferedReader br = new BufferedReader(isr);  
  19.             String line = null;  
  20.             while ((line = br.readLine()) != null)  
  21.                 System.out.println(type + ">>>" + line);  
  22.         } catch (IOException ioe) {  
  23.             ioe.printStackTrace();  
  24.         }  
  25.     }  
  26. }  

然后改造一下以上的“ping百度网址”的程序:

Java代码 

  1. import java.io.IOException;  
  2.   
  3. public class ProcessDemo {  
  4.     public static void main(String[] args) {  
  5.         try {  
  6.             Process process = Runtime.getRuntime().exec("ping www.baidu.com");  
  7.             new CleanInputCache(process.getInputStream(),"INFO").start();  
  8.             new CleanInputCache(process.getErrorStream(),"ERROR").start();  
  9.             process.waitFor();  
  10.             System.out.println("任务执行完毕!");  
  11.         } catch (IOException e) {  
  12.             // TODO Auto-generated catch block  
  13.             e.printStackTrace();  
  14.         } catch (InterruptedException e) {  
  15.             // TODO Auto-generated catch block  
  16.             e.printStackTrace();  
  17.         }  
  18.     }  
  19. }  

 大功告成,这样程序再也不用担心阻塞了,放心奔跑吧,process!!!

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值