隨筆-314  評(píng)論-209  文章-0  trackbacks-0

          一般我們?cè)趈ava中運(yùn)行其它類中的方法時(shí),無論是靜態(tài)調(diào)用,還是動(dòng)態(tài)調(diào)用,都是在當(dāng)前的進(jìn)程中執(zhí)行的,也就是說,只有一個(gè)java虛擬機(jī)實(shí)例在運(yùn)行。而有的時(shí)候,我們需要通過java代碼啟動(dòng)多個(gè)java子進(jìn)程。這樣做雖然占用了一些系統(tǒng)資源,但會(huì)使程序更加穩(wěn)定,因?yàn)樾聠?dòng)的程序是在不同的虛擬機(jī)進(jìn)程中運(yùn)行的,如果有一個(gè)進(jìn)程發(fā)生異常,并不影響其它的子進(jìn)程。

          在Java中我們可以使用兩種方法來實(shí)現(xiàn)這種要求。最簡單的方法就是通過Runtime中的exec方法執(zhí)行java classname。如果執(zhí)行成功,這個(gè)方法返回一個(gè)Process對(duì)象,如果執(zhí)行失敗,將拋出一個(gè)IOException錯(cuò)誤。下面讓我們來看一個(gè)簡單的例子。

                      

          // 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("被調(diào)用成功!");
           }
          }

          // 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運(yùn)行程序后,發(fā)現(xiàn)在C盤多了個(gè)Test1.txt文件,但在控制臺(tái)中并未出現(xiàn)“被調(diào)用成功!”的輸出信息。因此可以斷定,Test已經(jīng)被執(zhí)行成功,但因?yàn)槟撤N原因,Test的輸出信息未在Test_Exec的控制臺(tái)中輸出。這個(gè)原因也很簡單,因?yàn)槭褂胑xec建立的是Test_Exec的子進(jìn)程,這個(gè)子進(jìn)程并沒有自己的控制臺(tái),因此,它并不會(huì)輸出任何信息。

          如果要輸出子進(jìn)程的輸出信息,可以通過Process中的getInputStream得到子進(jìn)程的輸出流(在子進(jìn)程中輸出,在父進(jìn)程中就是輸入),然后將子進(jìn)程中的輸出流從父進(jìn)程的控制臺(tái)輸出。具體的實(shí)現(xiàn)代碼如下如示:

                      

          // 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中通過按行讀取子進(jìn)程的輸出信息,然后在Test_Exec_Out中按每行進(jìn)行輸出。上面討論的是如何得到子進(jìn)程的輸出信息。那么,除了輸出信息,還有輸入信息。既然子進(jìn)程沒有自己的控制臺(tái),那么輸入信息也得由父進(jìn)程提供。我們可以通過Process的getOutputStream方法來為子進(jìn)程提供輸入信息(即由父進(jìn)程向子進(jìn)程輸入信息,而不是由控制臺(tái)輸入信息)。我們可以看看如下的代碼:

                      

          // 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("由父進(jìn)程輸入的信息:" + 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("向子進(jìn)程輸出信息");
          bw.flush();
          bw.close(); // 必須得關(guān)閉流,否則無法向子進(jìn)程中輸入信息
          // System.in.read();
           }
          }

          從以上代碼可以看出,Test1得到由Test_Exec_In發(fā)過來的信息,并將其輸出。當(dāng)你不加bw.flash()和bw.close()時(shí),信息將無法到達(dá)子進(jìn)程,也就是說子進(jìn)程進(jìn)入阻塞狀態(tài),但由于父進(jìn)程已經(jīng)退出了,因此,子進(jìn)程也跟著退出了。如果要證明這一點(diǎn),可以在最后加上System.in.read(),然后通過任務(wù)管理器(在windows下)查看java進(jìn)程,你會(huì)發(fā)現(xiàn)如果加上bw.flush()和bw.close(),只有一個(gè)java進(jìn)程存在,如果去掉它們,就有兩個(gè)java進(jìn)程存在。這是因?yàn)椋绻麑⑿畔鹘oTest2,在得到信息后,Test2就退出了。

          在這里有一點(diǎn)需要說明一下,exec的執(zhí)行是異步的,并不會(huì)因?yàn)閳?zhí)行的某個(gè)程序阻塞而停止執(zhí)行下面的代碼。因此,可以在運(yùn)行test2后,仍可以執(zhí)行下面的代碼。

          exec方法經(jīng)過了多次的重載。上面使用的只是它的一種重載。它還可以將命令和參數(shù)分開,如exec(“java.test2”)可以寫成exec(“java”, “test2”)。exec還可以通過指定的環(huán)境變量運(yùn)行不同配置的java虛擬機(jī)。

          除了使用Runtime的exec方法建立子進(jìn)程外,還可以通過ProcessBuilder建立子進(jìn)程。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();
          … …
           }
          }

          在建立子進(jìn)程上,ProcessBuilder和Runtime類似,不同的ProcessBuilder使用start()方法啟動(dòng)子進(jìn)程,而Runtime使用exec方法啟動(dòng)子進(jìn)程。得到Process后,它們的操作就完全一樣的。

          ProcessBuilder和Runtime一樣,也可設(shè)置可執(zhí)行文件的環(huán)境信息、工作目錄等。下面的例子描述了如何使用ProcessBuilder設(shè)置這些信息。

                      

          ProcessBuilder pb = new ProcessBuilder("Command", "arg2", "arg2", ''');
          // 設(shè)置環(huán)境變量
          Map<String, String> env = pb.environment();
          env.put("key1", "value1");
          env.remove("key2");
          env.put("key2", env.get("key1") + "_test");
          pb.directory("..\abcd"); // 設(shè)置工作目錄
          Process p = pb.start(); // 建立子進(jìn)程

          posted on 2008-11-17 19:56 xzc 閱讀(691) 評(píng)論(3)  編輯  收藏 所屬分類: Java

          評(píng)論:
          # re: Java的多進(jìn)程運(yùn)行模式分析 2008-11-17 19:57 | xzc
          java Test a b  回復(fù)  更多評(píng)論
            
          # re: Java的多進(jìn)程運(yùn)行模式分析 2008-11-17 19:58 | xzc
          ETLImplProgDAO etlImplProgDAO = (ETLImplProgDAO) Class.forName("com.Test").newInstance();
          rtn = etlImplProgDAO.execute(workItemType, regionId, dataStime, dataEtime);  回復(fù)  更多評(píng)論
            
          # re: Java的多進(jìn)程運(yùn)行模式分析 2008-11-19 16:11 | xzc
          Runtime.getRuntime().exec("java -cp class2.jar com.Test a \"b c d\"")  回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 桃园市| 隆德县| 巨野县| 若羌县| 古交市| 阿拉善左旗| 天水市| 蒙自县| 盐城市| 综艺| 昂仁县| 抚远县| 双鸭山市| 噶尔县| 仁布县| 晋州市| 临清市| 舞阳县| 象州县| 甘孜县| 长沙县| 济阳县| 南城县| 竹北市| 千阳县| 随州市| 霍邱县| 正蓝旗| 应用必备| 麻栗坡县| 老河口市| 锡林郭勒盟| 平乡县| 黎平县| 阳泉市| 屯门区| 洛阳市| 得荣县| 塔城市| 宣城市| 星子县|