一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - 淺談Java多進(jìn)程程序的運行模式

淺談Java多進(jìn)程程序的運行模式

2020-01-15 14:30wbw1985 JAVA教程

這篇文章主要介紹了淺談Java多進(jìn)程程序的運行模式,包括對進(jìn)程阻塞問題的討論等,需要的朋友可以參考下

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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運行程序后,發(fā)現(xiàn)在C盤多了個Test1.txt文件,但在控制臺中并未出現(xiàn)"被調(diào)用成功!"的輸出信息。因此可以斷定,Test已經(jīng)被執(zhí)行成功,但因為某種原因,Test的輸出信息未在Test_Exec的控制臺中輸出。這個原因也很簡單,因為使用exec建立的是Test_Exec 的子進(jìn)程,這個子進(jìn)程并沒有自己的控制臺,因此,它并不會輸出任何信息。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 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)程沒有自己的控制臺,那么輸入信息也得由父進(jìn)程提供。我們可以通過 Process的getOutputStream方法來為子進(jìn)程提供輸入信息(即由父進(jìn)程向子進(jìn)程輸入信息,而不是由控制臺輸入信息)。我們可以看看如下的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 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()時,信息將無法到達(dá)子進(jìn)程,也就是說子進(jìn)程進(jìn)入阻塞狀態(tài),但由于父進(jìn)程已經(jīng)退出了,因此,子進(jìn)程也跟著退出了。如果要證明這一點,可以在最后加上 System.in.read(),然后通過任務(wù)管理器(在windows下)查看java進(jìn)程,你會發(fā)現(xiàn)如果加上bw.flush()和 bw.close(),只有一個java進(jìn)程存在,如果去掉它們,就有兩個java進(jìn)程存在。這是因為,如果將信息傳給Test2,在得到信息后, Test2就退出了。在這里有一點需要說明一下,exec的執(zhí)行是異步的,并不會因為執(zhí)行的某個程序阻塞而停止執(zhí)行下面的代碼。因此,可以在運行 test2后,仍可以執(zhí)行下面的代碼。
exec方法經(jīng)過了多次的重載。上面使用的只是它的一種重載。它還可以將命令和參數(shù)分開,如exec("java.test2")可以寫成exec("java", "test2")。exec還可以通過指定的環(huán)境變量運行不同配置的java虛擬機。

除了使用Runtime的exec方法建立子進(jìn)程外,還可以通過ProcessBuilder建立子進(jìn)程。ProcessBuilder的使用方法如下:

?
1
2
3
4
5
6
7
8
9
10
11
// 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()方法啟動子進(jìn)程,而Runtime使用exec方法啟動子進(jìn)程。得到Process后,它們的操作就完全一樣的。

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

?
1
2
3
4
5
6
7
8
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)程

進(jìn)程阻塞問題 
  由Process代表的進(jìn)程在某些平臺上有時候并不能很好的工作,特別是在對代表進(jìn)程的標(biāo)準(zhǔn)輸入流、輸出流和錯誤輸出進(jìn)行操作時,如果使用不慎,有可能導(dǎo)致進(jìn)程阻塞,甚至死鎖。
如果將以上事例中的從標(biāo)準(zhǔn)輸出重讀取信息的語句修改為從錯誤輸出流中讀取: 

?
1
stdout = new BufferedReader(new InputStreamReader(p.getErrorStream()));

  那么程序?qū)l(fā)生阻塞,不能執(zhí)行完成,而是hang在那里。
  當(dāng)進(jìn)程啟動后,就會打開標(biāo)準(zhǔn)輸出流和錯誤輸出流準(zhǔn)備輸出,當(dāng)進(jìn)程結(jié)束時,就會關(guān)閉他們。在以上例子中,錯誤輸出流沒有數(shù)據(jù)要輸出,標(biāo)準(zhǔn)輸出流中有數(shù)據(jù)輸出。由于標(biāo)準(zhǔn)輸出流中的數(shù)據(jù)沒有被讀取,進(jìn)程就不會結(jié)束,錯誤輸出流也就不會被關(guān)閉,因此在調(diào)用readLine()方法時,整個程序就會被阻塞。為了解決這個問題,可以根據(jù)輸出的實際先后,先讀取標(biāo)準(zhǔn)輸出流,然后讀取錯誤輸出流。
   但是,很多時候不能很明確的知道輸出的先后,特別是要操作標(biāo)準(zhǔn)輸入的時候,情況就會更為復(fù)雜。這時候可以采用線程來對標(biāo)準(zhǔn)輸出、錯誤輸出和標(biāo)準(zhǔn)輸入進(jìn)行分別處理,根據(jù)他們之間在業(yè)務(wù)邏輯上的關(guān)系決定讀取那個流或者寫入數(shù)據(jù)。
   針對標(biāo)準(zhǔn)輸出流和錯誤輸出流所造成的問題,可以使用ProcessBuilder的redirectErrorStream()方法將他們合二為一,這時候只要讀取標(biāo)準(zhǔn)輸出的數(shù)據(jù)就可以了。
當(dāng)在程序中使用Process的waitFor()方法時,特別是在讀取之前調(diào)用waitFor()方法時,也有可能造成阻塞。可以用線程的方法來解決這個問題,也可以在讀取數(shù)據(jù)后,調(diào)用waitFor()方法等待程序結(jié)束。
總之,解決阻塞的方法在這里我介紹使用ProcessBuilder類,利用redirectErrorStream方法將標(biāo)準(zhǔn)輸出流和錯誤輸出流合二為一,在用start()方法啟動進(jìn)程后,先從標(biāo)準(zhǔn)輸出中讀取數(shù)據(jù),然后調(diào)用waitFor()方法等待進(jìn)程結(jié)束。
如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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();
  }
}

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日韩精品中文字幕视频一区 | 日本在线播放 | 香蕉eeww99国产精品 | 欧洲网色偷偷亚洲男人的天堂 | 日韩欧美一区二区三区 | 精品国产精品国产 | 色老妇 | 成年人在线视频观看 | 天天操天天爽天天射 | 特级夫妻大片免费在线播放 | 亚洲va精品中文字幕 | 日本三级免费观看 | 波多野结衣中文丝袜字幕 | 亚洲欧美成人综合久久久 | 午夜精品久久久 | 三级网站午夜三级 | 国产成人综合久久精品红 | www久久久| 国产乱子伦真实china | 日韩免费一级片 | 非洲特级特黄aa大片 | 成品人视频w免费观看w | 美女和男人一起差差 | eeuss免费快捷 | 风间由美一区二区播放合集 | 国产香蕉一区二区精品视频 | 87影院在线观看视频在线观看 | 91交换论坛| 成人国产午夜在线视频 | 国产午夜小视频 | 成人18在线观看 | 久久久久久久99精品免费观看 | 国内精品91东航翘臀女神在线 | 久久精品国产免费播放 | 免费一级特黄特色大片在线 | 日本三级做a全过程在线观看 | 青春学堂在线观看 | 小伙无套内射老女人 | 无码国产成人777爽死 | 国产精品对白刺激久久久 | 亚洲精品一区在线观看 |