Java中Process類的使用與注意事項(xiàng)說明
Process類的使用與注意事項(xiàng)說明
1、在項(xiàng)目開發(fā)中
經(jīng)常會遇到調(diào)用其它程序功能的業(yè)務(wù)需求,在java中通常有兩種實(shí)現(xiàn)方法
Runtime runtime = Runtime.getRuntime(); Process p = runtime.exec(cmd);
Process p=new ProcessBuilder(cmd).start();
2、在這里就需要認(rèn)識一下process類
process是一個(gè)抽象的類,它包含6個(gè)抽象的方法
abstract public OutputStream getOutputStream(); abstract public InputStream getInputStream(); abstract public InputStream getErrorStream(); abstract public int waitFor() throws InterruptedException; abstract public int exitValue(); abstract public void destroy();
process類提供獲取子進(jìn)程的輸入流、子進(jìn)程的輸出流、子進(jìn)程的錯(cuò)誤流、等待進(jìn)程完成、檢查進(jìn)程的推出狀態(tài)以及銷毀進(jìn)程的方法;在這里需要提及的是創(chuàng)建的子進(jìn)程沒有自己的控制臺或終端,其所有的io操作都是通過(輸入流、輸出流、錯(cuò)誤流)重定向到父進(jìn)程中。
3、來說說今天業(yè)務(wù)需求[waitfor()]:
我需要在linux下首先將一個(gè)文件copy到指定的文件夾下面,之后需要將該文件夾下面的文件加入指定的jar中,那么問題就來了,必須保證其先后順序,也就書說再執(zhí)行第二個(gè)命令的時(shí)候第一個(gè)命令必須完成。
public void cmd(String cmd){
try {
Process ps= Runtime.getRuntime().exec(cmd);
} catch (Exception e) {
logger.info(e.getMessage(),e);
}
}
main函數(shù)如下:
public static void main(String[] args){
String copy="cp -rf "+source+" "+target;
String jar="jar -uvf "+jar+" "+file;
cmd(copy);
cmd(jar);
}
但是結(jié)果是新生成的jar中壓根沒有新加入的文件,但是文件確實(shí)copy到了指定的文件夾中,也就是誰兩個(gè)命令都執(zhí)行了,問題的關(guān)鍵就是“異步”,這時(shí)候需要waitFor()的介入
public void cmd(String cmd){
try {
Process ps= Runtime.getRuntime().exec(cmd);
ps.waitFor();
} catch (Exception e) {
logger.info(e.getMessage(),e);
}
}
那么問題就解決了!
4、前不久遇到一個(gè)奇怪的問題就是ajax調(diào)用沒有返回值
我在service中實(shí)現(xiàn)了process的調(diào)用。
String[] commands = { commandGenerate,commandPublish};
PrintWriter printWriter = response.getWriter();
for (String comm : commands) {
Runtime runtime = Runtime.getRuntime();
try {
logger.info("command is :{}",comm);
Process process = runtime.exec(comm, null, null);
BufferedInputStream inputStream = new BufferedInputStream(
process.getInputStream());
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream));
String line;
while (bufferedReader.read() != -1) {
line = bufferedReader.readLine();
System.out.println(line);
}
bufferedReader.close();
inputStream.close();
printWriter.println("success");
} catch (IOException e) {
logger.error(e.getMessage(), e);
printWriter.println(e.getMessage());
}
}
printWriter.flush();
printWriter.close();
對應(yīng)的controller為:
State state = new State();
String message="";
try {
message = missionService.syntax(taskName, response);
} catch (InterruptedException e) {
e.printStackTrace();
}
state.setSuccess(true);
state.setMessage(message.trim());
return state;
打印state.getMessage()確實(shí)可以獲得值,但是state返回就是空,剛開始以為是ajax的timeout時(shí)間的問題:修改了ajax的timeout時(shí)間仍然不行;將message直接賦值,然thread等待20s,結(jié)果是可以返回的,所以問題最終定為于service的這段實(shí)現(xiàn)。
原因分析:在上面提及了,process創(chuàng)建的子進(jìn)程沒有自己的控制臺或終端,其所有的io操作都是通過(輸入流、輸出流、錯(cuò)誤流)重定向到父進(jìn)程中,如果該可執(zhí)行程序的輸入、輸出或者錯(cuò)誤輸出比較多的話,而由于運(yùn)行窗口的標(biāo)準(zhǔn)輸入、輸出等緩沖區(qū)有大小的限制,則可能導(dǎo)致子進(jìn)程阻塞,甚至產(chǎn)生死鎖,其解決方法就是在waitfor()方法之前讀出窗口的標(biāo)準(zhǔn)輸出、輸出、錯(cuò)誤緩沖區(qū)中的內(nèi)容。
for (String comm : commands) {
logger.info("the comm time is:"+new Date().getTime()+" the comm is:"+comm);
Runtime runtime = Runtime.getRuntime();
Process p=null;
try {
p = runtime.exec(comm ,null,null);
final InputStream is1 = p.getInputStream();
final InputStream is2 = p.getErrorStream();
new Thread() {
public void run() {
BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));
try {
String line1 = null;
while ((line1 = br1.readLine()) != null) {
if (line1 != null){
logger.info("p.getInputStream:"+line1);
if(line1.indexOf("syntax check result:")!=-1){
builder.append(line1);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
finally{
try {
is1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));
try {
String line2 = null ;
while ((line2 = br2.readLine()) != null ) {
if (line2 != null){
}
}
} catch (IOException e) {
e.printStackTrace();
}
finally{
try {
is2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
p.waitFor();
p.destroy();
} catch (Exception e) {
try{
p.getErrorStream().close();
p.getInputStream().close();
p.getOutputStream().close();
}
catch(Exception ee){}
}
}
java的process實(shí)例講解
package cn.itcast.process;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
public class ProcessTest implements Runnable{
private Process process = null;
public ProcessTest() {
try {
process = Runtime.getRuntime().exec("java MyTest");
new Thread(this).start();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ProcessTest processTest = new ProcessTest();
processTest.send();
}
public void send()
{
OutputStream outputStream = process.getOutputStream();
while(true)
{
try {
outputStream.write("this is good\r\n".getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void run() {
InputStream inputStream = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String str = null;
try {
while(true)
{
str = bufferedReader.readLine();
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
理解下面這句話就能更加容易的理解上面的代碼
在java程序中可以用Process類的實(shí)例對象來表示子進(jìn)程,子進(jìn)程的標(biāo)準(zhǔn)輸入和輸出不在連接到鍵盤和顯示器,而是以管道流的形式連接到父進(jìn)程的 一個(gè)輸出流和輸入流對象上-à好好理解這句代碼就能看懂那個(gè)程序。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
javaweb中ajax請求后臺servlet(實(shí)例)
下面小編就為大家?guī)硪黄猨avaweb中ajax請求后臺servlet(實(shí)例)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06
詳解Springboot+React項(xiàng)目跨域訪問問題
這篇文章主要介紹了詳解Springboot+React項(xiàng)目跨域訪問問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-11-11
java多線程編程之使用thread類創(chuàng)建線程
在Java中創(chuàng)建線程有兩種方法:使用Thread類和使用Runnable接口。在使用Runnable接口時(shí)需要建立一個(gè)Thread實(shí)例2014-01-01
java通過Callable和Future來接收線程池的執(zhí)行結(jié)果
這篇文章主要介紹了java通過Callable和Future來接收線程池的執(zhí)行結(jié)果,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
Java查詢時(shí)間段(startTime--endTime)間的數(shù)據(jù)方式
這篇文章主要介紹了Java查詢時(shí)間段(startTime--endTime)間的數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
springboot數(shù)據(jù)庫密碼加密的配置方法
這篇文章主要給大家介紹了關(guān)于springboot數(shù)據(jù)庫密碼加密的配置方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04

