程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 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 env = pb.environment();

env.put(“key1”, “value1”);

env.remove(“key2”);

env.put(“key2”, env.get(“key1”) + “_test”);

pb.directory(“abcd”); // 設置工作目錄

Process p = pb.start(); // 建立子進程

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved