Java进程的创建

     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 Runnable is used
    * to create a thread, starting the thread causes the object's
    * run  method to be called in that separately executing
    * thread.
    * 

* The general contract of the method run 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 command;
    private File directory ;
    private Map environment;
    private boolean redirectErrorStream ;
    private Redirect[] redirects ;

    public ProcessBuilder( List 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 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组装成一个字符串的方法。


你可能感兴趣的:(Java学习笔记)