熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

Java程序多進程運行模式的實例分析

2013-11-23 19:42:33  來源: Java高級技術 
一般我們在java中運行其它類中的方法時無論是靜態調用還是動態調用都是在當前的進程中執行的也就是說只有一個java虛擬機實例在運行而有的時候我們需要通過java代碼啟動多個java子進程這樣做雖然占用了一些系統資源但會使程序更加穩定因為新啟動的程序是在不同的虛擬機進程中運行的如果有一個進程發生異常並不影響其它的子進程

  在Java中我們可以使用兩種方法來實現這種要求最簡單的方法就是通過Runtime中的exec方法執行java classname如果執行成功這個方法返回一個Process對象如果執行失敗將拋出一個IOException錯誤下面讓我們來看一個簡單的例子
// Testjava文件
import javaio*;
public class Test
{
 public static void main(String[] args)
 {
  FileOutputStream fOut = new FileOutputStream(c:\Testtxt);
  fOutclose();
  Systemoutprintln(被調用成功!);
 }
}

// Test_Execjava
public class Test_Exec
{
 public static void main(String[] args)
 {
  Runtime run = RuntimegetRuntime();
  Process p = runexec(java test);
 }


  通過java Test_Exec運行程序後發現在C盤多了個Testtxt文件但在控制台中並未出現被調用成功!的輸出信息因此可以斷定Test已經被執行成功但因為某種原因Test的輸出信息未在Test_Exec的控制台中輸出這個原因也很簡單因為使用exec建立的是Test_Exec的子進程這個子進程並沒有自己的控制台因此它並不會輸出任何信息

  如果要輸出子進程的輸出信息可以通過Process中的getInputStream得到子進程的輸出流(在子進程中輸出在父進程中就是輸入)然後將子進程中的輸出流從父進程的控制台輸出具體的實現代碼如下如示

// Test_Exec_Outjava
import javaio*;
public class Test_Exec_Out
{
 public static void main(String[] args)
 {
  Runtime run = RuntimegetRuntime();
  Process p = runexec(java test);
  BufferedInputStream in = new BufferedInputStream(pgetInputStream());
  BufferedReader br = new BufferedReader(new InputStreamReader(in));
  String s;
  while ((s = brreadLine()) != null)
   Systemoutprintln(s);
 }

  從上面的代碼可以看出在Test_Exec_Outjava中通過按行讀取子進程的輸出信息然後在Test_Exec_Out中按每行進行輸出 上面討論的是如何得到子進程的輸出信息那麼除了輸出信息還有輸入信息既然子進程沒有自己的控制台那麼輸入信息也得由父進程提供我們可以通過Process的getOutputStream方法來為子進程提供輸入信息(即由父進程向子進程輸入信息而不是由控制台輸入信息)

  我們可以看看如下的代碼


// Testjava文件
import javaio*;
public class Test
{
 public static void main(String[] args)
 {
  BufferedReader br = new BufferedReader(new InputStreamReader(Systemin));
  Systemoutprintln(由父進程輸入的信息 + brreadLine());
 }
}

// Test_Exec_Injava
import javaio*;
public class Test_Exec_In
{
 public static void main(String[] args)
 {
  Runtime run = RuntimegetRuntime();
  Process p = runexec(java test);
  BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(pgetOutputStream()));
  bwwrite(向子進程輸出信息);
bwflush();
  bwclose(); // 必須得關閉流否則無法向子進程中輸入信息
  // Systeminread();
 }
}
  從以上代碼可以看出Test得到由Test_Exec_In發過來的信息並將其輸出當你不加bwflash()和bwclose()時信息將無法到達子進程也就是說子進程進入阻塞狀態但由於父進程已經退出了因此子進程也跟著退出了如果要證明這一點可以在最後加上Systeminread()然後通過任務管理器(在windows下)查看java進程你會發現如果加上bwflush()和bwclose()只有一個java進程存在如果去掉它們就有兩個java進程存在這是因為如果將信息傳給Test在得到信息後Test就退出了在這裡有一點需要說明一下exec的執行是異步的並不會因為執行的某個程序阻塞而停止執行下面的代碼因此可以在運行test仍可以執行下面的代碼

  exec方法經過了多次的重載上面使用的只是它的一種重載它還可以將命令和參數分開如exec(javatest)可以寫成exec(java test)exec還可以通過指定的環境變量運行不同配置的java虛擬機

  除了使用Runtime的exec方法建立子進程外還可以通過ProcessBuilder建立子進程ProcessBuilder的使用方法如下

// Test_Exec_Outjava
import javaio*;
public class Test_Exec_Out
{
 public static void main(String[] args)
 {
  ProcessBuilder pb = new ProcessBuilder(java test);
  Process p = pbstart();
  … …
 }
}
  在建立子進程上ProcessBuilder和Runtime類似不同的ProcessBuilder使用start()方法啟動子進程而Runtime使用exec方法啟動子進程得到Process後它們的操作就完全一樣的

ProcessBuilder和Runtime一樣也可設置可執行文件的環境信息工作目錄等

ProcessBuilder pb = new ProcessBuilder(Command arg arg );
// 設置環境變量
Map env = pbenvironment();
envput(key value);
envremove(key);
envput(key envget(key) + _test);
pbdirectory(\abcd); // 設置工作目錄
Process p = pbstart(); // 建立子進程


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27333.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.