Java进程的创建

来源:互联网 发布:如何做好商务工作 知乎 编辑:程序博客网 时间:2024/05/20 00:35
     Java线程创建有两种形式,一种是继承Thread,一种是实现Runnable接口。
    private class NewThread extends Thread {        @Override        public void run(){       // do Something       }    }    private class NewRunnable implements Runnable {        @Override        public void run(){       // do Something       }    }
     代码中使用:
   new NewThread().start();   new Thread( new NewRunnable()).start();
     其实两者本质上是相同的,Thread、Runnable源码如下:
   class Thread implements Runnable    public interface Runnable {   /**    * When an object implementing interface <code>Runnable</code> is used    * to create a thread, starting the thread causes the object's    * <code>run </code> method to be called in that separately executing    * thread.    * <p>    * The general contract of the method <code>run</code> is that it may    * take any action whatsoever.    *    * @see     java.lang.Thread#run()    */   public abstract void run();
可以看到Thread其实本质上实现了Runnable接口;

而Java中进程该如何创建呢,有两种实现方法:一种是使用ProcessBuilder.start来创建;一种是使用Runntime.exec实现;

一、使用ProcessBuilder.start创建
1、使用:
       ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "ipconfig/all");       Process process = null;        try {              process = pb.start();       } catch (IOException e) {              e.printStackTrace();       }              System.out.println(process.isAlive());       Scanner scanner = new Scanner (process.getInputStream());               while (scanner.hasNextLine()) {              System.out.println(scanner.nextLine());       }       scanner.close();

2、先来看进程Process的主体源码:
public abstract class Process {           abstract public OutputStream getOutputStream();   //获取进程的输出流       abstract public InputStream getInputStream();    //获取进程的输入流     abstract public InputStream getErrorStream();   //获取进程的错误流     abstract public int waitFor() throws InterruptedException;   //让进程等待     abstract public int exitValue();   //获取进程的退出标志     abstract public void destroy();   //摧毁进程    public Process destroyForcibly() {        destroy();        return this ;    }    public boolean isAlive() {        try {            exitValue();            return false ;        } catch(IllegalThreadStateException e) {            return true ;        }    }}

3、ProcessBuilder的构造函数:
public final class ProcessBuilder{           private List<String> command;    private File directory ;    private Map<String,String> environment;    private boolean redirectErrorStream ;    private Redirect[] redirects ;    public ProcessBuilder( List<String > command) {        if (command == null)            throw new NullPointerException();        this.command = command;    }    public ProcessBuilder( String... command) {        this.command = new ArrayList <>(command.length );        for (String arg : command)            this.command .add(arg);    }}
     支持两种构造函数,一种是List形式,一种是不定长参数形式;

4、ProcessBuilder是通过start方法来启动Process:
public Process start() throws IOException {    // Must convert to array first -- a malicious user-supplied    // list might try to circumvent the security check.    String[] cmdarray = command.toArray(new String[command .size()]);    cmdarray = cmdarray.clone();    for (String arg : cmdarray)        if (arg == null )            throw new NullPointerException();    // Throws IndexOutOfBoundsException if command is empty    String prog = cmdarray[0];    SecurityManager security = System.getSecurityManager();    if (security != null)        security.checkExec(prog);    String dir = directory == null ? null : directory.toString();    for ( int i = 1; i < cmdarray.length; i++) {        if (cmdarray[i].indexOf('\u0000' ) >= 0) {            throw new IOException( "invalid null character in command" );        }    }    try {        return ProcessImpl.start(cmdarray,                                 environment,                                 dir,                                 redirects,                                 redirectErrorStream);    } catch (IOException | IllegalArgumentException e) {        ......    }}
     前面是对commands的一系列处理,最终通过
     ProcessImpl.start(cmdarray,environment,dir,redirects,redirectErrorStream);
来启动进程。

5、来看看ProcessImpl(和Android中Context,ContextImpl略像)
final class ProcessImpl extends Process {               static Process start(String cmdarray[],             java.util.Map<String,String> environment,             String dir, ProcessBuilder.Redirect[] redirects,             boolean redirectErrorStream)throws IOException{               String envblock = ProcessEnvironment.toEnvironmentBlock(environment);               try {                      .......                             return new ProcessImpl(cmdarray, envblock, dir, stdHandles, redirectErrorStream);               } finally {                      .......               }        }}
可以看到最终返回的Process的实际类型是ProcessImpl对象;ProcessImpl是抽象类Process的具体实现类。

二、使用Runtime.exec来创建
1、使用
    String cmd = "cmd "+ "/c " +"ipconfig/all" ;    Process process = Runtime.getRuntime().exec(cmd);    Scanner scanner = new Scanner (process.getInputStream());        while(scanner.hasNextLine()){        System.out.println(scanner.nextLine());    }    scanner.close();

2、Runtime类:
public class Runtime {    private static Runtime currentRuntime = new Runtime();    public static Runtime getRuntime() {        return currentRuntime ;    }    private Runtime() {}}
很明显的单例模式。

3、Runtime#exec:
    public Process exec(String command) throws IOException {        return exec(command, null , null );    }           public Process exec(String command, String[] envp, File dir)        throws IOException {        if (command.length() == 0)            throw new IllegalArgumentException( "Empty command");        StringTokenizer st = new StringTokenizer (command);        String[] cmdarray = new String[st.countTokens()];        for (int i = 0; st.hasMoreTokens(); i++)            cmdarray[i] = st.nextToken();        return exec(cmdarray, envp, dir);    }    public Process exec(String[] cmdarray, String[] envp, File dir)        throws IOException {        return new ProcessBuilder (cmdarray)            . environment(envp)            .directory(dir)            .start();    }
    可以看到最终依然是调用ProcessBuilder.start来创建的,两者原理实质相同;只是由于构造函数的不同,Runtime.exec方法只支持将所有commands组装成一个字符串的方法。


0 0