java什么时候创建进程,Java创建进程
Java創建進程
1 進程的概念 1
1.1 進程的概念 1
1.2 進程的特征 1
1.3 進程與線程區別 1
2 進程的創建 1
2.1 JAVA進程的創建 1
2.1.1 ProcessBuilder 2
2.1.2 Runtime 3
2.1.3 Process 4
2.2 實例 5
2.2.1 創建子進程 5
2.2.2 進程阻塞問題 7
2.2.3 在java中執行java程序 11
1 進程的概念
1.1 進程的概念
進程是操作系統結構的基礎;是一個正在執行的程序;計算機中正在運行的程序實例;可以分配給處理器并由處理器執行的一個實體;由單一順序的執行顯示,一個當前狀態和一組相關的系統資源所描述的活動單元。
第一,進程是一個實體。每一個進程都有它自己的地址空間,一般情況下,包括文本區域(text region)、數據區域(data region)和堆棧(stack region)。文本區域存儲處理器執行的代碼;數據區域存儲變量和進程執行期間使用的動態分配的內存;堆棧區域存儲著活動過程調用的指令和本地變量。
第 二,進程是一個“執行中的程序”。程序是一個沒有生命的實體,只有處理器賦予程序生命時,它才能成為一個活動的實體,我們稱其為進程。
1.2 進程的特征
動態性:進程的實質是程序在多道程序系統中的一次執行過程,進程是動態產生,動態消亡的。
并發性:任何進程都可以同其他進程一起并發執行
獨立性:進程是一個能獨立運行的基本單位,同時也是系統分配資源和調度的獨立單位;
異步性:由于進程間的相互制約,使進程具有執行的間斷性,即進程按各自獨立的、不可預知的速度向前推進
結構特征:進程由程序、數據和進程控制塊三部分組成。
多個不同的進程可以包含相同的程序:一個程序在不同的數據集里就構成不同的進程,能得到不同的結果;但是執行過程中,程序不能發生改變。
1.3 進程與線程區別
進程和線程的主要差別在于它們是不同的操作系統資源管理方式。進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其它進程產生影 響,而線程只是一個進程中的不同執行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程的程 序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對于一些要求同時進行并且又要共享某些變量的并發操作,只能用線程,不能用進
程。
2 進程的創建
2.1 Java進程的創建
Java提供了兩種方法用來啟動進程或其它程序:
(1)使用Runtime的exec()方法
(2)使用ProcessBuilder的start()方法
2.1.1 ProcessBuilder
ProcessBuilder類是J2SE 1.5在java.lang中新添加的一個新類,此類用于創建操作系統進程,它提供一種啟動和管理進程(也就是應用程序)的方法。在J2SE 1.5之前,都是由Process類處來實現進程的控制管理。
每個 ProcessBuilder 實例管理一個進程屬性集。start() 方法利用這些屬性創建一個新的 Process 實例。start() 方法可以從同一實例重復調用,以利用相同的或相關的屬性創建新的子進程。
每個進程生成器管理這些進程屬性:
命令 是一個字符串列表,它表示要調用的外部程序文件及其參數(如果有)。在此,表示有效的操作系統命令的字符串列表是依賴于系統的。例如,每一個總體變量,通常都要成為此列表中的元素,但有一些操作系統,希望程序能自己標記命令行字符串——在這種系統中,Java 實現可能需要命令確切地包含這兩個元素。
環境 是從變量 到值 的依賴于系統的映射。初始值是當前進程環境的一個副本(請參閱 System.getenv())。
工作目錄。默認值是當前進程的當前工作目錄,通常根據系統屬性 user.dir 來命名。
redirectErrorStream 屬性。最初,此屬性為 false,意思是子進程的標準輸出和錯誤輸出被發送給兩個獨立的流,這些流可以通過 Process.getInputStream() 和 Process.getErrorStream() 方法來訪問。如果將值設置為 true,標準錯誤將與標準輸出合并。這使得關聯錯誤消息和相應的輸出變得更容易。在此情況下,合并的數據可從
Process.getInputStream() 返回的流讀取,而從 Process.getErrorStream() 返回的流讀取將直接到達文件尾。
修改進程構建器的屬性將影響后續由該對象的 start() 方法啟動的進程,但從不會影響以前啟動的進程或 Java 自身的進程。大多數錯誤檢查由 start() 方法執行。可以修改對象的狀態,但這樣 start() 將會失敗。例如,將命令屬性設置為一個空列表將不會拋出異常,除非包含了 start()。
注意,此類不是同步的。如果多個線程同時訪問一個 ProcessBuilder,而其中至少一個線程從結構上修改了其中一個屬性,它必須 保持外部同步。
Java代碼??
構造方法摘要
ProcessBuilder(List?command)
利用指定的操作系統程序和參數構造一個進程生成器。
ProcessBuilder(String...?command)
利用指定的操作系統程序和參數構造一個進程生成器。
方法摘要
List?command()
返回此進程生成器的操作系統程序和參數。
ProcessBuilder?command(List?command)
設置此進程生成器的操作系統程序和參數。
ProcessBuilder?command(String...?command)
設置此進程生成器的操作系統程序和參數。
File?directory()
返回此進程生成器的工作目錄。
ProcessBuilder?directory(File?directory)
設置此進程生成器的工作目錄。
Map?environment()
返回此進程生成器環境的字符串映射視圖。
boolean?redirectErrorStream()
通知進程生成器是否合并標準錯誤和標準輸出。
ProcessBuilder?redirectErrorStream(boolean?redirectErrorStream)
設置此進程生成器的?redirectErrorStream?屬性。
Process?start()
使用此進程生成器的屬性啟動一個新進程。
2.1.2 Runtime
每個 Java 應用程序都有一個 Runtime 類實例,使應用程序能夠與其運行的環境相連接。可以通過 getRuntime 方法獲取當前運行時。
應用程序不能創建自己的 Runtime 類實例。但可以通過 getRuntime 方法獲取當前Runtime運行時對象的引用。一旦得到了一個當前的Runtime對象的引用,就可以調用Runtime對象的方法去控制Java虛擬機的狀態和行為。
Java代碼??
void?addShutdownHook(Thread?hook)
注冊新的虛擬機來關閉掛鉤。
int?availableProcessors()
向?Java?虛擬機返回可用處理器的數目。
Process?exec(String?command)
在單獨的進程中執行指定的字符串命令。
Process?exec(String[]?cmdarray)
在單獨的進程中執行指定命令和變量。
Process?exec(String[]?cmdarray,?String[]?envp)
在指定環境的獨立進程中執行指定命令和變量。
Process?exec(String[]?cmdarray,?String[]?envp,?File?dir)
在指定環境和工作目錄的獨立進程中執行指定的命令和變量。
Process?exec(String?command,?String[]?envp)
在指定環境的單獨進程中執行指定的字符串命令。
Process?exec(String?command,?String[]?envp,?File?dir)
在有指定環境和工作目錄的獨立進程中執行指定的字符串命令。
void?exit(int?status)
通過啟動虛擬機的關閉序列,終止當前正在運行的?Java?虛擬機。
long?freeMemory()
返回?Java?虛擬機中的空閑內存量。
void?gc()
運行垃圾回收器。
InputStream?getLocalizedInputStream(InputStream?in)
已過時。?從?JDK?1.1?開始,將本地編碼字節流轉換為?Unicode?字符流的首選方法是使用?InputStreamReader?和?BufferedReader?類。
OutputStream?getLocalizedOutputStream(OutputStream?out)
已過時。?從?JDK?1.1?開始,將?Unicode?字符流轉換為本地編碼字節流的首選方法是使用?OutputStreamWriter、BufferedWriter?和?PrintWriter?類。
static?Runtime?getRuntime()
返回與當前?Java?應用程序相關的運行時對象。
void?halt(int?status)
強行終止目前正在運行的?Java?虛擬機。
void?load(String?filename)
加載作為動態庫的指定文件名。
void?loadLibrary(String?libname)
加載具有指定庫名的動態庫。
long?maxMemory()
返回?Java?虛擬機試圖使用的最大內存量。
boolean?removeShutdownHook(Thread?hook)
取消注冊某個先前已注冊的虛擬機關閉掛鉤。
void?runFinalization()
運行掛起?finalization?的所有對象的終止方法。
static?void?runFinalizersOnExit(boolean?value)
已過時。?此方法本身具有不安全性。它可能對正在使用的對象調用終結方法,而其他線程正在操作這些對象,從而導致不正確的行為或死鎖。
long?totalMemory()
返回?Java?虛擬機中的內存總量。
void?traceInstructions(boolean?on)
啟用/禁用指令跟蹤。
void?traceMethodCalls(boolean?on)
啟用/禁用方法調用跟蹤。
2.1.3 Process
不管通過那種方法啟動進程后,都會返回一個Process類的實例代表啟動的進程,該實例可用來控制進程并獲得相關信息。Process 類提供了執行從進程輸入、執行輸出到進程、等待進程完成、檢查進程的退出狀態以及銷毀(殺掉)進程的方法:
Java代碼??
void?destroy()
殺掉子進程。
一般情況下,該方法并不能殺掉已經啟動的進程,不用為好。
int?exitValue()
返回子進程的出口值。
只有啟動的進程執行完成、或者由于異常退出后,exitValue()方法才會有正常的返回值,否則拋出異常。
InputStream?getErrorStream()
獲取子進程的錯誤流。
如果錯誤輸出被重定向,則不能從該流中讀取錯誤輸出。
InputStream?getInputStream()
獲取子進程的輸入流。
可以從該流中讀取進程的標準輸出。
OutputStream?getOutputStream()
獲取子進程的輸出流。
寫入到該流中的數據作為進程的標準輸入。
int?waitFor()
導致當前線程等待,如有必要,一直要等到由該?Process?對象表示的進程已經終止。
通過該類提供的方法,可以實現與啟動的進程之間通信,達到交互的目的。
2.2 實例
2.2.1 創建子進程
要創建子進程可以通過使用使用ProcessBuilder的start()方法和Runtime的exec()方法。
(1)Runtime.exec()
Java代碼??
import?java.io.BufferedReader;
import?java.io.File;
import?java.io.InputStreamReader;
public?class?Test1?{
public?static?void?main(String[]?args)?{
try?{
Process?p?=?null;
String?line?=?null;
BufferedReader?stdout?=?null;
//list?the?files?and?directorys?under?C:\
p?=?Runtime.getRuntime().exec("CMD.exe?/C?dir",?null,?new?File("C:\\"));
stdout?=?new?BufferedReader(new?InputStreamReader(p
.getInputStream()));
while?((line?=?stdout.readLine())?!=?null)?{
System.out.println(line);
}
stdout.close();
//echo?the?value?of?NAME
p?=?Runtime.getRuntime().exec("CMD.exe?/C?echo?%NAME%",?new?String[]?{"NAME=TEST"});
stdout?=?new?BufferedReader(new?InputStreamReader(p
.getInputStream()));
while?((line?=?stdout.readLine())?!=?null)?{
System.out.println(line);
}
stdout.close();
}?catch?(Exception?e)?{
e.printStackTrace();
}
}
(2)ProcessBuilder
Java代碼??
import?java.io.BufferedReader;
import?java.io.File;
import?java.io.InputStreamReader;
import?java.util.ArrayList;
import?java.util.List;
public?class?Test2?{
public?static?void?main(String[]?args)?{
try?{
List?list?=?new?ArrayList();
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("dir");
pb?=?new?ProcessBuilder(list);
pb.directory(new?File("C:\\"));
p?=?pb.start();
stdout?=?new?BufferedReader(new?InputStreamReader(p
.getInputStream()));
while?((line?=?stdout.readLine())?!=?null)?{
System.out.println(line);
}
stdout.close();
//echo?the?value?of?NAME
pb?=?new?ProcessBuilder();
pb.command(new?String[]?{"CMD.exe",?"/C",?"echo?%NAME%"});
pb.environment().put("NAME",?"TEST");
p?=?pb.start();
stdout?=?new?BufferedReader(new?InputStreamReader(p
.getInputStream()));
while?((line?=?stdout.readLine())?!=?null)?{
System.out.println(line);
}
stdout.close();
}?catch?(Exception?e)?{
e.printStackTrace();
}
}
從啟動其他程序的Java進程看,已啟動的其他程序輸出就是一個普通的輸入流,可以通過getInputStream()和getErrorStream來獲取。對于一般輸出文本的進程來說,可以將InputStream封裝成BufferedReader,然后就可以一行一行的對進程的標準輸出進行處理。
通常,一個程序/進程在執行結束后會向操作系統返回一個整數值,0一般代表執行成功,非0表示執行出現問題。有兩種方式可以用來獲取進程的返回值。一是利用waitFor(),該方法是阻塞的,執導進程執行完成后再返回。該方法返回一個代表進程返回值的整數值。另一個方法是調用exitValue()方法,該方法是非阻塞的,調用立即返回。但是如果進程沒有執行完成,則拋出異常。
2.2.2 進程阻塞問題
由Process代表的進程在某些平臺上有時候并不能很好的工作,特別是在對代表進程的標準輸入流、輸出流和錯誤輸出進行操作時,如果使用不慎,有可能導致進程阻塞,甚至死鎖。
如果將以上事例中的從標準輸出重讀取信息的語句修改為從錯誤輸出流中讀取:
stdout = new BufferedReader(new InputStreamReader(p.getErrorStream()));
那么程序將發生阻塞,不能執行完成,而是hang在那里。
當進程啟動后,就會打開標準輸出流和錯誤輸出流準備輸出,當進程結束時,就會關閉他們。在以上例子中,錯誤輸出流沒有數據要輸出,標準輸出流中有數據輸出。由于標準輸出流中的數據沒有被讀取,進程就不會結束,錯誤輸出流也就不會被關閉,因此在調用readLine()方法時,整個程序就會被阻塞。為了解決這個問題,可以根據輸出的實際先后,先讀取標準輸出流,然后讀取錯誤輸出流。
但是,很多時候不能很明確的知道輸出的先后,特別是要操作標準輸入的時候,情況就會更為復雜。這時候可以采用線程來對標準輸出、錯誤輸出和標準輸入進行分別處理,根據他們之間在業務邏輯上的關系決定讀取那個流或者寫入數據。
針對標準輸出流和錯誤輸出流所造成的問題,可以使用ProcessBuilder的redirectErrorStream()方法將他們合二為一,這時候只要讀取標準輸出的數據就可以了。
當在程序中使用Process的waitFor()方法時,特別是在讀取之前調用waitFor()方法時,也有可能造成阻塞。可以用線程的方法來解決這個問題,也可以在讀取數據后,調用waitFor()方法等待程序結束。
總之,解決阻塞的方法應該有兩種:
(1)使用ProcessBuilder類,利用redirectErrorStream方法將標準輸出流和錯誤輸出流合二為一,在用start()方法啟動進程后,先從標準輸出中讀取數據,然后調用waitFor()方法等待進程結束。
如:
Java代碼??
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?list?=?new?ArrayList();
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();
}
}
(2)使用線程
Java代碼??
import?java.util.*;
import?java.io.*;
class?StreamWatch?extends?Thread?{
InputStream?is;
String?type;
List?output?=?new?ArrayList();
boolean?debug?=?false;
StreamWatch(InputStream?is,?String?type)?{
this(is,?type,?false);
}
StreamWatch(InputStream?is,?String?type,?boolean?debug)?{
this.is?=?is;
this.type?=?type;
this.debug?=?debug;
}
public?void?run()?{
try?{
PrintWriter?pw?=?null;
InputStreamReader?isr?=?new?InputStreamReader(is);
BufferedReader?br?=?new?BufferedReader(isr);
String?line?=?null;
while?((line?=?br.readLine())?!=?null)?{
output.add(line);
if?(debug)
System.out.println(type?+?">"?+?line);
}
if?(pw?!=?null)
pw.flush();
}?catch?(IOException?ioe)?{
ioe.printStackTrace();
}
}
public?List?getOutput()?{
return?output;
}
}
Java代碼??
public?class?Test5?{
public?static?void?main(String?args[])?{
try?{
List?list?=?new?ArrayList();
ProcessBuilder?pb?=?null;
Process?p?=?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:\\"));
p?=?pb.start();
//?process?error?and?output?message
StreamWatch?errorWatch?=?new?StreamWatch(p.getErrorStream(),
"ERROR");
StreamWatch?outputWatch?=?new?StreamWatch(p.getInputStream(),
"OUTPUT");
//?start?to?watch
errorWatch.start();
outputWatch.start();
//wait?for?exit
int?exitVal?=?p.waitFor();
//print?the?content?from?ERROR?and?OUTPUT
System.out.println("ERROR:?"?+?errorWatch.getOutput());
System.out.println("OUTPUT:?"?+?outputWatch.getOutput());
System.out.println("the?return?code?is?"?+?exitVal);
}?catch?(Throwable?t)?{
t.printStackTrace();
}
}
}
2.2.3 在java中執行java程序
執行一個Java程序的關鍵在于:
(1)知道JAVA虛擬機的位置,即java.exe或者java的路徑
(2)知道要執行的java程序的位置
(3)知道該程序所依賴的其他類的位置
舉一個例子,一目了然。
(1)待執行的Java類
Java代碼??
public?class?MyTest?{
public?static?void?main(String[]?args)?{
System.out.println("OUTPUT?one");
System.out.println("OUTPUT?two");
System.err.println("ERROR?1");
System.err.println("ERROR?2");
for(int?i?=?0;?i?
{
System.out.printf("args[%d]?=?%s.",?i,?args[i]);
}
}
}
(2)執行該類的程序
Java代碼??
import?java.util.*;
import?java.io.*;
class?StreamWatch?extends?Thread?{
InputStream?is;
String?type;
List?output?=?new?ArrayList();
boolean?debug?=?false;
StreamWatch(InputStream?is,?String?type)?{
this(is,?type,?false);
}
StreamWatch(InputStream?is,?String?type,?boolean?debug)?{
this.is?=?is;
this.type?=?type;
this.debug?=?debug;
}
public?void?run()?{
try?{
PrintWriter?pw?=?null;
InputStreamReader?isr?=?new?InputStreamReader(is);
BufferedReader?br?=?new?BufferedReader(isr);
String?line?=?null;
while?((line?=?br.readLine())?!=?null)?{
output.add(line);
if?(debug)
System.out.println(type?+?">"?+?line);
}
if?(pw?!=?null)
pw.flush();
}?catch?(IOException?ioe)?{
ioe.printStackTrace();
}
}
public?List?getOutput()?{
return?output;
}
}
Java代碼??
public?class?Test6?{
public?static?void?main(String?args[])?{
try?{
List?list?=?new?ArrayList();
ProcessBuilder?pb?=?null;
Process?p?=?null;
String?java?=?System.getProperty("java.home")?+?File.separator?+?"bin"?+?File.separator?+?"java";
String?classpath?=?System.getProperty("java.class.path");
//?list?the?files?and?directorys?under?C:\
list.add(java);
list.add("-classpath");
list.add(classpath);
list.add(MyTest.class.getName());
list.add("hello");
list.add("world");
list.add("good?better?best");
pb?=?new?ProcessBuilder(list);
p?=?pb.start();
System.out.println(pb.command());
//?process?error?and?output?message
StreamWatch?errorWatch?=?new?StreamWatch(p.getErrorStream(),
"ERROR");
StreamWatch?outputWatch?=?new?StreamWatch(p.getInputStream(),
"OUTPUT");
//?start?to?watch
errorWatch.start();
outputWatch.start();
//wait?for?exit
int?exitVal?=?p.waitFor();
//print?the?content?from?ERROR?and?OUTPUT
System.out.println("ERROR:?"?+?errorWatch.getOutput());
System.out.println("OUTPUT:?"?+?outputWatch.getOutput());
System.out.println("the?return?code?is?"?+?exitVal);
}?catch?(Throwable?t)?{
t.printStackTrace();
}
總結
以上是生活随笔為你收集整理的java什么时候创建进程,Java创建进程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 总是存不到钱怎么办?没有钱也可以理财吗?
- 下一篇: 浦发信用卡万用金怎么申请 六种方式任你选