发现问题的过程是这样的,我使用staf在远程的机器上执行命令,并且需要获取远程命令执行的返回值。因此写了如下代码。其中"staf " + ipAddress + " process query handle " + handle是获取staf具体的handle信息。如:staf 9.12.207.120 process query handle 89,具体输出的信息应该如下,因此process的return code应该是1,可是debug的时候发现程序一直hang在那里,一直在抛出IllegalThreadStateException之后休眠然后循环, hung了很久都没有返回。
C:\Documents and Settings\Administrator>staf 9.12.207.120 process query handle 8
9
Response
--------
Handle : 89
Handle Name :
Title :
Workload :
Shell :
Command : python -u C:\\ 。。。。。。。。(省略了命令)
Parms :
Workdir :
Focus : Background
User Name :
Key :
PID : 3156
Start Mode : Async
Start Date-Time: 20120223-20:02:56
End Date-Time : 20120223-20:02:57
Return Code : 1
程序代码如下:
Process p = null;
// The queryExitValue variable represents whether the staf query worked.
// It does not represent whether the command that had been executed via staf was successful.
int queryExitValue = -1;
// If retrieve status fails, wait a bit and try again.
while (queryExitValue != 0)
{
p = Runtime.getRuntime().exec("staf " + ipAddress + " process query handle " + handle);
// Wait for the query command to end by looping until p.exitValue() no longer results in
// an IllegalThreadStateException.
boolean queryDone = false;
while (!queryDone)
{
try
{
queryExitValue = p.exitValue();
queryDone = true;
}
catch (IllegalThreadStateException itse)
{
Thread.sleep(5000);
}
}
if (queryExitValue != 0)
{
Thread.sleep(delayBetweenAttempts);
retrieveStatusAttempts++;
if (retrieveStatusAttempts > maximumRetrieveStatusAttempts)
{
throw new Exception("Unable to retrieve status. Exit value " + p.exitValue());
}
}
}
google原因查到API中有说到
http://docs.oracle.com/javase/1.5.0/docs/api/
The ProcessBuilder.start()
and Runtime.exec
methods create a native process and return aninstance of a subclass of Process
that can be used tocontrol the process and obtain information about it. The classProcess
provides methods for performing input from theprocess, performing output to the process, waiting for the processto complete, checking the exit status of the process, anddestroying (killing) the process.
Themethods that create processes may not work well for specialprocesses on certain native platforms, such as native windowingprocesses, daemon processes, Win16/DOS processes on MicrosoftWindows, or shell scripts. Thecreated subprocess does not have its own terminal orconsole. All its standard io (i.e. stdin, stdout, stderr)operations will be redirected to the parent processthrough three streams (getOutputStream()
,getInputStream()
,getErrorStream()
).The parent process uses these streams to feed input to and getoutput from the subprocess. Because some native platforms onlyprovide limited buffer size for standard input and output streams,failure to promptly write the input stream or read the outputstream of the subprocess may cause the subprocess to block, andeven deadlock.
The subprocess is not killed when there are no more references tothe Process
object, but rather the subprocesscontinues executing asynchronously.
There is no requirement that a process represented by aProcess
object execute asynchronously or concurrentlywith respect to the Java process that owns the Process
object
原因在这里:
Process.exitValue() 采用非阻塞的方式返回,如果没有立即拿到返回值,则抛出异常
Process.waitFor() 当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。但是如果我们在调用此方法时,如果不注意的话,很容易出现主线程阻塞,Process也挂起的情况。在调用waitFor() 的时候,Process需要向主线程汇报运行状况,所以要注意清空缓存区,即InputStream和ErrorStreamp = Runtime.getRuntime().exec("staf " + ipAddress + " process query handle " + handle);
final InputStream is1 = p.getInputStream();
new Thread(new Runnable(){
public void run() {
BufferedReader br = new BufferedReader(new InputStreamReader(is1));
try {
String outputLine = null;
while((outputLine=br.readLine())!= null)
commandOutput.add(outputLine);
}catch (IOException e) {
e.printStackTrace();
}
}
}).start();
InputStream is2 = p.getErrorStream();
BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));
StringBuilder buf = new StringBuilder();
String line = null;
while((line = br2.readLine()) != null) buf.append(line);
System.out.println("result:" + buf);
while (br2.readLine() != null);
try {
p.waitFor();
}catch (InterruptedException e){
e.printStackTrace();
}
queryExitValue=p.exitValue();
System.out.println( p.exitValue());
加入对输入和输出缓冲流的处理后这个问题顺利解决