Java Process的问题

发现问题的过程是这样的,我使用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    : <None>
Title          : <None>
Workload       : <None>
Shell          : <Default Shell>
Command        : python -u C:\\ 。。。。。。。。(省略了命令)
Parms          : <None>
Workdir        : <None>
Focus          : Background
User Name      : <None>
Key            : <None>
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 Processobject


原因在这里:

Process.exitValue() 采用非阻塞的方式返回,如果没有立即拿到返回值,则抛出异常

Process.waitFor() 当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。但是如果我们在调用此方法时,如果不注意的话,很容易出现主线程阻塞,Process也挂起的情况。在调用waitFor() 的时候,Process需要向主线程汇报运行状况,所以要注意清空缓存区,即InputStream和ErrorStream
解决方法:

p = 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());

加入对输入和输出缓冲流的处理后这个问题顺利解决

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

惹不起的程咬金

来都来了,不赏点银子么

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值