最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2015年11月05日 16:54:05   作者:wbw1985  
這篇文章主要介紹了淺談Java多進(jìn)程程序的運(yùn)行模式,包括對(duì)進(jìn)程阻塞問題的討論等,需要的朋友可以參考下

一般我們?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)這種要求。最簡(jiǎn)單的方法就是通過Runtime中的exec方法執(zhí)行java classname。如果執(zhí)行成功,這個(gè)方法返回一個(gè)Process對(duì)象,如果執(zhí)行失敗,將拋出一個(gè)IOException錯(cuò)誤。下面讓我們來看一個(gè)簡(jiǎn)單的例子。

// 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è)原因也很簡(jiǎn)單,因?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)程

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

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

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

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(); 
  } 
} 

相關(guān)文章

  • Spring-webflux?響應(yīng)式編程的實(shí)例詳解

    Spring-webflux?響應(yīng)式編程的實(shí)例詳解

    Spring 提供了兩個(gè)并行堆棧,一種是基于帶有 Spring MVC 和 Spring Data 結(jié)構(gòu)的 Servlet API,另一個(gè)是完全反應(yīng)式堆棧,它利用了 Spring WebFlux 和 Spring Data 的反應(yīng)式存儲(chǔ)庫(kù),這篇文章主要介紹了Spring-webflux?響應(yīng)式編程,需要的朋友可以參考下
    2022-09-09
  • maven利用tomcat插件部署遠(yuǎn)程Linux服務(wù)器的步驟詳解

    maven利用tomcat插件部署遠(yuǎn)程Linux服務(wù)器的步驟詳解

    Maven已經(jīng)是Java的項(xiàng)目管理常用方式,下面這篇文章主要給大家介紹了關(guān)于maven利用tomcat插件部署遠(yuǎn)程Linux服務(wù)器的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • 基于String變量的兩種創(chuàng)建方式(詳解)

    基于String變量的兩種創(chuàng)建方式(詳解)

    下面小編就為大家?guī)硪黄赟tring變量的兩種創(chuàng)建方式(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • 詳解Spring-bean的循環(huán)依賴以及解決方式

    詳解Spring-bean的循環(huán)依賴以及解決方式

    這篇文章主要介紹了詳解Spring-bean的循環(huán)依賴以及解決方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-09-09
  • 簡(jiǎn)單了解JAVA NIO

    簡(jiǎn)單了解JAVA NIO

    這篇文章主要介紹了JAVA NIO的的相關(guān)資料,文中講解非常細(xì)致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • Springboot中攔截GET請(qǐng)求獲取請(qǐng)求參數(shù)驗(yàn)證合法性核心方法

    Springboot中攔截GET請(qǐng)求獲取請(qǐng)求參數(shù)驗(yàn)證合法性核心方法

    這篇文章主要介紹了Springboot中攔截GET請(qǐng)求獲取請(qǐng)求參數(shù)驗(yàn)證合法性,在Springboot中創(chuàng)建攔截器攔截所有GET類型請(qǐng)求,獲取請(qǐng)求參數(shù)驗(yàn)證內(nèi)容合法性防止SQL注入,這種方法適用攔截get類型請(qǐng)求,需要的朋友可以參考下
    2023-08-08
  • JPA之QueryDSL-JPA使用指南

    JPA之QueryDSL-JPA使用指南

    Springdata-JPA是對(duì)JPA使用的封裝,Querydsl-JPA也是基于各種ORM之上的一個(gè)通用查詢框架,使用它的API類庫(kù)可以寫出Java代碼的sql,下面就來介紹一下JPA之QueryDSL-JPA使用指南
    2023-11-11
  • SpringBoot 嵌入式web容器的啟動(dòng)原理詳解

    SpringBoot 嵌入式web容器的啟動(dòng)原理詳解

    這篇文章主要介紹了SpringBoot 嵌入式web容器的啟動(dòng)原理詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2021-11-11
  • SpringBoot+Redis實(shí)現(xiàn)查找附近用戶的示例代碼

    SpringBoot+Redis實(shí)現(xiàn)查找附近用戶的示例代碼

    SpringDataRedis提供了十分簡(jiǎn)單的地理位置定位的功能,本文主要介紹了SpringBoot+Redis實(shí)現(xiàn)查找附近用戶的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • Java中四種訪問控制權(quán)限解析(private、default、protected、public)

    Java中四種訪問控制權(quán)限解析(private、default、protected、public)

    java當(dāng)中有4種訪問修飾限定符privat、default(默認(rèn)訪問權(quán)限),protected以及public,本文就詳細(xì)的介紹一下這四種方法的具體使用,感興趣的可以了解一下
    2023-05-05

最新評(píng)論

东乌珠穆沁旗| 嵊泗县| 探索| 神池县| 玉屏| 大余县| 大同市| 金湖县| 湖南省| 梓潼县| 天镇县| 潮州市| 鄂州市| 竹北市| 肇源县| 本溪| 六安市| 瓮安县| 江津市| 浮山县| 浏阳市| 辽宁省| 建阳市| 兴安县| 永修县| 都兰县| 九江市| 绩溪县| 玛多县| 增城市| 治县。| 杭州市| 南皮县| 宁波市| 汾西县| 富蕴县| 昭平县| 威海市| 潍坊市| 漳浦县| 天气|