您的位置:首页 > 编程语言 > Java开发

java runtime exec 运行挂起的问题

2011-11-24 10:51 309 查看
这两天让一个同事去做一个ORACLE数据定时备份的工作,结果她写完代码后发现可以导出备份文件,但是使用RUNTIME的时候没办法结束,也就是说这个进程一直处于挂起的状态,是什么原因呢?

为了解决这个问题到网上找了下,有这么一段英文资料:

The next version of Savant is going to focus heavily on the stand-alone runtime and support for dialects and plugins. Supporting all that is largely handled by using a simple executor framework I wrote around Java 1.4 and lower’s Runtime.exec method. A few
things to keep in mind when using this:

Always read from the streams prior to calling waitFor. Otherwise you could end up waiting forever on Windows and other OS platforms whose I/O buffers can’t store enough from standard out and standard error to ensure the program has finished. These platforms
will pause the execution of whatever is running until something reads the buffered content from standard out and standard error. I would imagine all platforms suffer from this, but some platforms have larger buffers than others. Needless to say, always read
from the streams first.
Always read from standard error first. I ran across a bug where some OS platforms will always open standard out, but never close it. What this means is that if you read from standard out first and the process only writes to standard error, you’ll hang forever
waiting to read. If you read from standard error first, you’ll always be okay on these platforms because the OS seems to shutdown standard error. I think however, that the best way to handle all cases is to check both standard error and standard out for readiness
and only read from them if they have something to offer. The downside I could see here is that error isn’t ready, but eventually will be.

可以看出来:

1.要在调用waitFor()方法之前读取数据流

2.要先从标准错误流中读取,然后再读取标准输出流,因为runtime默认先读取错误流,一旦错误流没被读取,这个进程就回被挂起

找到了原因,那么可以使用如下的解决方法:

测试类如下:

public class TESTRuntime {

public String cmdexeStr = "exp test/test file=d:/daochu.dmp tables=(t_test)";

public String startRunTime(){
try {
Process proc = Runtime.getRuntime().exec(cmdexeStr);
ProcessStreamUtil errorProcStream = new ProcessStreamUtil(proc.getErrorStream(),"Error");
ProcessStreamUtil outputProcStream = new ProcessStreamUtil(proc.getInputStream(),"Output");
errorProcStream.start();
outputProcStream.start();
int num = proc.waitFor();
System.out.println("------num:"+num);
proc.destroy();
                    } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

public static void main(String[] args) {
System.out.println("------------start run--------------");
TESTRuntime test = new TESTRuntime();
test.startRunTime();
System.out.println("------------end run--------------");
}

}


解决挂起的多线程类如下:

public class ProcessStreamUtil extends Thread{

private InputStream inputStream;

private String type;

private int i=0;

public ProcessStreamUtil(InputStream inputStream,String type){
this.inputStream = inputStream;
this.type = type;
}

public void run() {
System.out.println("------type:"+type+"--------start--------------");
try {
i = i+1;
InputStreamReader isr = new InputStreamReader(inputStream);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
if (type.equals("Error")){
System.out.println("------i:"+i+"-------error:\n"+line);
}else{
System.out.println("------i:"+i+"--------debug:\n"+line);
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
System.out.println("------type:"+type+"--------end--------------");
}

public InputStream getInputStream() {
return inputStream;
}

public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

}


当然后来经过同事的提醒,发现不开辟一个新的线程处理错误流,也可以

代码如下:

public class TESTRuntime {

public String cmdexeStr = "exp test/test file=d:/daochu.dmp tables=(t_test)";

public String startRunTime(){
try {
Process proc = Runtime.getRuntime().exec(cmdexeStr);
InputStream errorProcStream = proc.getErrorStream();
InputStream outputProcStream = proc.getInputStream();
InputStreamReader errorRead = new InputStreamReader(errorProcStream);
InputStreamReader outputRead = new InputStreamReader(outputProcStream);
BufferedReader errorbr = new BufferedReader(errorRead);
String errorline = null;
while ((errorline = errorbr.readLine()) != null) {
System.out.println("------error:/n"+errorline);
}
BufferedReader outputbr = new BufferedReader(outputRead);
String outputline = null;
while ((outputline = outputbr.readLine()) != null) {
System.out.println("------debug:/n"+outputline);
}
int num = proc.waitFor();
System.out.println("------num:"+num);
proc.destroy();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

public static void main(String[] args) {
System.out.println("------------start run--------------");
TESTRuntime test = new TESTRuntime();
test.startRunTime();
System.out.println("------------end run--------------");
}

}

有人肯定会问了,那么开辟线程处理错误流和不开辟线程处理错误流有什么区别呢?

在此我做了个实验,对这两种解决挂起的方法做了运行效率的比较,发现使用多线程处理数据流的效率要略高于单线程处理,即多线程使用的时间比不使用要少!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息