淺談Java多過程法式的運轉形式。本站提示廣大學習愛好者:(淺談Java多過程法式的運轉形式)文章只能為提供參考,不一定能成為您想要的結果。以下是淺談Java多過程法式的運轉形式正文
普通我們在java中運轉其它類中的辦法時,不管是靜態挪用,照樣靜態挪用,都是在以後的過程中履行的,也就是說,只要一個java虛擬機實例在運轉。而有的時刻,我們須要經由過程java代碼啟動多個java子過程。如許做固然占用了一些體系資本,但會使法式加倍穩固,由於新啟動的法式是在分歧的虛擬機過程中運轉的,假如有一個過程產生異常,其實不影響其它的子過程。
在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(); // 樹立子過程
過程壅塞成績
由Process代表的過程在某些平台上有時刻其實不能很好的任務,特殊是在對代表過程的尺度輸出流、輸入流和毛病輸入停止操作時,假如應用失慎,有能夠招致過程壅塞,乃至逝世鎖。
假如將以上事例中的從尺度輸入重讀守信息的語句修正為從毛病輸入流中讀取:
stdout = new BufferedReader(new InputStreamReader(p.getErrorStream()));
那末法式將產生壅塞,不克不及履行完成,而是hang在那邊。
當過程啟動後,就會翻開尺度輸入流和毛病輸入流預備輸入,當過程停止時,就會封閉他們。在以上例子中,毛病輸入流沒稀有據要輸入,尺度輸入流中稀有據輸入。因為尺度輸入流中的數據沒有被讀取,過程就不會停止,毛病輸入流也就不會被封閉,是以在挪用readLine()辦法時,全部法式就會被壅塞。為懂得決這個成績,可以依據輸入的現實前後,先讀取尺度輸入流,然後讀取毛病輸入流。
然則,許多時刻不克不及很明白的曉得輸入的前後,特殊是要操作尺度輸出的時刻,情形就會更加龐雜。這時候候可以采取線程來對尺度輸入、毛病輸入和尺度輸出停止分離處置,依據他們之間在營業邏輯上的關系決議讀取誰人流或許寫入數據。
針對尺度輸入流和毛病輸入流所形成的成績,可使用ProcessBuilder的redirectErrorStream()辦法將他們合二為一,這時候候只需讀取尺度輸入的數據便可以了。
當在法式中應用Process的waitFor()辦法時,特殊是在讀取之前挪用waitFor()辦法時,也有能夠形成壅塞。可以用線程的辦法來處理這個成績,也能夠在讀取數據後,挪用waitFor()辦法期待法式停止。
總之,處理壅塞的辦法在這裡我引見應用ProcessBuilder類,應用redirectErrorStream辦法將尺度輸入流和毛病輸入流合二為一,在用start()辦法啟動過程後,先從尺度輸入中讀取數據,然後挪用waitFor()辦法期待過程停止。
如:
import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; public class Test3 { public static void main(String[] args) { try { List<String> list = new ArrayList<String>(); ProcessBuilder pb = null; Process p = null; String line = null; BufferedReader stdout = null; //list the files and directorys under C:\ list.add("CMD.EXE"); list.add("/C"); list.add("dir1"); pb = new ProcessBuilder(list); pb.directory(new File("C:\\")); //merge the error output with the standard output pb.redirectErrorStream(true); p = pb.start(); //read the standard output stdout = new BufferedReader(new InputStreamReader(p .getInputStream())); while ((line = stdout.readLine()) != null) { System.out.println(line); } int ret = p.waitFor(); System.out.println("the return code is " + ret); stdout.close(); } catch (Exception e) { e.printStackTrace(); } }