java的多程序執行模式分析
阿新 • • 發佈:2019-01-22
一般我們在java中執行其它類中的方法時,無論是靜態呼叫,還是動態呼叫,都是在當前的程序中執行的,也就是說,只有一個java虛擬機器例項在執行。而有的時候,我們需要通過java程式碼啟動多個java子程序。這樣做雖然佔用了一些系統資源,但會使程式更加穩定,因為新啟動的程式是在不同的虛擬機器程序中執行的,如果有一個程序發生異常,並不影響其它的子程序。
在Java中我們可以使用兩種方法來實現這種要求。最簡單的方法就是通過Runtime中的exec方法執行java classname。如果執行成功,這個方法返回一個Process物件,如果執行失敗,將丟擲一個IOException錯誤。下面讓我們來看一個簡單的例子。
通過java Test_Exec執行程式後,發現在C盤多了個Test1.txt檔案,但在控制檯中並未出現"被呼叫成功!"的輸出資訊。因此可以斷定,Test已經被執行成功,但因為某種原因,Test的輸出資訊未在Test_Exec的控制檯中輸出。這個原因也很簡單,因為使用exec建立的是Test_Exec的子程序,這個子程序並沒有自己的控制檯,因此,它並不會輸出任何資訊。
如果要輸出子程序的輸出資訊,可以通過Process中的getInputStream得到子程序的輸出流(在子程序中輸出,在父程序中就是輸入),然後將子程序中的輸出流從父程序的控制檯輸出。具體的實現程式碼如下如示:
從上面的程式碼可以看出,在Test_Exec_Out.java中通過按行讀取子程序的輸出資訊,然後在Test_Exec_Out中按每行進行輸出。 上面討論的是如何得到子程序的輸出資訊。那麼,除了輸出資訊,還有輸入資訊。既然子程序沒有自己的控制檯,那麼輸入資訊也得由父程序提供。我們可以通過Process的getOutputStream方法來為子程序提供輸入資訊(即由父程序向子程序輸入資訊,而不是由控制檯輸入資訊)。我們可以看看如下的程式碼:
從以上程式碼可以看出,Test1得到由Test_Exec_In發過來的資訊,並將其輸出。當你不加bw.flash()和bw.close()時,資訊將無法到達子程序,也就是說子程序進入阻塞狀態,但由於父程序已經退出了,因此,子程序也跟著退出了。如果要證明這一點,可以在最後加上System.in.read(),然後通過工作管理員(在windows下)檢視java程序,你會發現如果加上bw.flush()和bw.close(),只有一個java程序存在,如果去掉它們,就有兩個java程序存在。這是因為,如果將資訊傳給Test2,在得到資訊後,Test2就退出了。在這裡有一點需要說明一下,exec的執行是非同步的,並不會因為執行的某個程式阻塞而停止執行下面的程式碼。因此,可以在執行test2後,仍可以執行下面的程式碼。
exec方法經過了多次的過載。上面使用的只是它的一種過載。它還可以將命令和引數分開,如exec("java.test2")可以寫成exec("java", "test2")。exec還可以通過指定的環境變數執行不同配置的java虛擬機器。
除了使用Runtime的exec方法建立子程序外,還可以通過ProcessBuilder建立子程序。ProcessBuilder的使用方法如下:
在建立子程序上,ProcessBuilder和Runtime類似,不同的ProcessBuilder使用start()方法啟動子程序,而Runtime使用exec方法啟動子程序。得到Process後,它們的操作就完全一樣的。
ProcessBuilder和Runtime一樣,也可設定可執行檔案的環境資訊、工作目錄等。下面的例子描述瞭如何使用ProcessBuilder設定這些資訊。
裝載於:http://dev.yesky.com/284/2659284.shtm
在Java中我們可以使用兩種方法來實現這種要求。最簡單的方法就是通過Runtime中的exec方法執行java classname。如果執行成功,這個方法返回一個Process物件,如果執行失敗,將丟擲一個IOException錯誤。下面讓我們來看一個簡單的例子。
// Test1.java檔案 import java.io.*; public class Test { public static void main(String[] args) { FileOutputStream fOut = new FileOutputStream("c:\\Test1.txt"); fOut.close(); System.out.println("被呼叫成功!"); } } // Test_Exec.java public class Test_Exec { public static void main(String[] args) { Runtime run = Runtime.getRuntime(); Process p = run.exec("java test1"); } } |
通過java Test_Exec執行程式後,發現在C盤多了個Test1.txt檔案,但在控制檯中並未出現"被呼叫成功!"的輸出資訊。因此可以斷定,Test已經被執行成功,但因為某種原因,Test的輸出資訊未在Test_Exec的控制檯中輸出。這個原因也很簡單,因為使用exec建立的是Test_Exec的子程序,這個子程序並沒有自己的控制檯,因此,它並不會輸出任何資訊。
如果要輸出子程序的輸出資訊,可以通過Process中的getInputStream得到子程序的輸出流(在子程序中輸出,在父程序中就是輸入),然後將子程序中的輸出流從父程序的控制檯輸出。具體的實現程式碼如下如示:
// Test_Exec_Out.java import java.io.*; public class Test_Exec_Out { public static void main(String[] args) { Runtime run = Runtime.getRuntime(); Process p = run.exec("java test1"); BufferedInputStream in = new BufferedInputStream(p.getInputStream()); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String s; while ((s = br.readLine()) != null) System.out.println(s); } } |
從上面的程式碼可以看出,在Test_Exec_Out.java中通過按行讀取子程序的輸出資訊,然後在Test_Exec_Out中按每行進行輸出。 上面討論的是如何得到子程序的輸出資訊。那麼,除了輸出資訊,還有輸入資訊。既然子程序沒有自己的控制檯,那麼輸入資訊也得由父程序提供。我們可以通過Process的getOutputStream方法來為子程序提供輸入資訊(即由父程序向子程序輸入資訊,而不是由控制檯輸入資訊)。我們可以看看如下的程式碼:
// Test2.java檔案 import java.io.*; public class Test { public static void main(String[] args) { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("由父程序輸入的資訊:" + br.readLine()); } } // Test_Exec_In.java import java.io.*; public class Test_Exec_In { public static void main(String[] args) { Runtime run = Runtime.getRuntime(); Process p = run.exec("java test2"); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(p.getOutputStream())); bw.write("向子程序輸出資訊"); bw.flush(); bw.close(); // 必須得關閉流,否則無法向子程序中輸入資訊 // System.in.read(); } } |
從以上程式碼可以看出,Test1得到由Test_Exec_In發過來的資訊,並將其輸出。當你不加bw.flash()和bw.close()時,資訊將無法到達子程序,也就是說子程序進入阻塞狀態,但由於父程序已經退出了,因此,子程序也跟著退出了。如果要證明這一點,可以在最後加上System.in.read(),然後通過工作管理員(在windows下)檢視java程序,你會發現如果加上bw.flush()和bw.close(),只有一個java程序存在,如果去掉它們,就有兩個java程序存在。這是因為,如果將資訊傳給Test2,在得到資訊後,Test2就退出了。在這裡有一點需要說明一下,exec的執行是非同步的,並不會因為執行的某個程式阻塞而停止執行下面的程式碼。因此,可以在執行test2後,仍可以執行下面的程式碼。
exec方法經過了多次的過載。上面使用的只是它的一種過載。它還可以將命令和引數分開,如exec("java.test2")可以寫成exec("java", "test2")。exec還可以通過指定的環境變數執行不同配置的java虛擬機器。
除了使用Runtime的exec方法建立子程序外,還可以通過ProcessBuilder建立子程序。ProcessBuilder的使用方法如下:
// Test_Exec_Out.java import java.io.*; public class Test_Exec_Out { public static void main(String[] args) { ProcessBuilder pb = new ProcessBuilder("java", "test1"); Process p = pb.start(); … … } } |
在建立子程序上,ProcessBuilder和Runtime類似,不同的ProcessBuilder使用start()方法啟動子程序,而Runtime使用exec方法啟動子程序。得到Process後,它們的操作就完全一樣的。
ProcessBuilder和Runtime一樣,也可設定可執行檔案的環境資訊、工作目錄等。下面的例子描述瞭如何使用ProcessBuilder設定這些資訊。
ProcessBuilder pb = new ProcessBuilder("Command", "arg2", "arg2", '''); // 設定環境變數 Map<String, String> env = pb.environment(); env.put("key1", "value1"); env.remove("key2"); env.put("key2", env.get("key1") + "_test"); pb.directory("..\abcd"); // 設定工作目錄 Process p = pb.start(); // 建立子程序 |