Java進程的建立,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 <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組裝成一個字串的方法。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。