一般我們在java中運行其它類中的方法時
無論是靜態調用
還是動態調用
都是在當前的進程中執行的
也就是說
只有一個java虛擬機實例在運行
而有的時候
我們需要通過java代碼啟動多個java子進程
這樣做雖然占用了一些系統資源
但會使程序更加穩定
因為新啟動的程序是在不同的虛擬機進程中運行的
如果有一個進程發生異常
並不影響其它的子進程
在Java中我們可以使用兩種方法來實現這種要求
最簡單的方法就是通過Runtime中的exec方法執行java classname
如果執行成功
這個方法返回一個Process對象
如果執行失敗
將拋出一個IOException錯誤
下面讓我們來看一個簡單的例子
// Test
java文件
import java
io
*;
public class Test
{
public static void main(String[] args)
{
FileOutputStream fOut = new FileOutputStream(
c:\Test
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 test
);
}
}
通過java Test_Exec運行程序後
發現在C盤多了個Test
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 test
);
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_Outjava中通過按行讀取子進程的輸出信息然後在Test_Exec_Out中按每行進行輸出 上面討論的是如何得到子進程的輸出信息那麼除了輸出信息還有輸入信息既然子進程沒有自己的控制台那麼輸入信息也得由父進程提供我們可以通過Process的getOutputStream方法來為子進程提供輸入信息(即由父進程向子進程輸入信息而不是由控制台輸入信息)
我們可以看看如下的代碼
// Test
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 test
);
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(p
getOutputStream()));
bw
write(
向子進程輸出信息
);
bw
flush();
bw
close(); // 必須得關閉流
否則無法向子進程中輸入信息
// System
in
read();
}
}
從以上代碼可以看出
Test
得到由Test_Exec_In發過來的信息
並將其輸出
當你不加bw
flash()和bw
close()時
信息將無法到達子進程
也就是說子進程進入阻塞狀態
但由於父進程已經退出了
因此
子進程也跟著退出了
如果要證明這一點
可以在最後加上System
in
read()
然後通過任務管理器(在windows下)查看java進程
你會發現如果加上bw
flush()和bw
close()
只有一個java進程存在
如果去掉它們
就有兩個java進程存在
這是因為
如果將信息傳給Test
在得到信息後
Test
就退出了
在這裡有一點需要說明一下
exec的執行是異步的
並不會因為執行的某個程序阻塞而停止執行下面的代碼
因此
可以在運行test
後
仍可以執行下面的代碼
exec方法經過了多次的重載
上面使用的只是它的一種重載
它還可以將命令和參數分開
如exec(
java
test
)可以寫成exec(
java
test
)
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
test
);
Process p = pb
start();
… …
}
}
在建立子進程上
ProcessBuilder和Runtime類似
不同的ProcessBuilder使用start()方法啟動子進程
而Runtime使用exec方法啟動子進程
得到Process後
它們的操作就完全一樣的
ProcessBuilder和Runtime一樣
也可設置可執行文件的環境信息
工作目錄等
ProcessBuilder pb = new ProcessBuilder(
Command
arg
arg
);
// 設置環境變量
Map env = pb
environment();
env
put(
key
value
);
env
remove(
key
);
env
put(
key
env
get(
key
) +
_test
);
pb
directory(
\abcd
); // 設置工作目錄
Process p = pb
start(); // 建立子進程
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27333.html