Runtime.exec Process.getInputStream和Process.waitFor()的问题

时间:2012-01-20 07:39:04

标签: java multiprocessing

我已经编写了一个代码来检查HSQL,JBoss,Radius(AAA服务器)和MySQL是否正在运行。代码是用inifinte while循环编写的,以便持续监控。现在我测试了这个服务(让我们说吧) hsql)正在运行,然后/bin/bash -c ps -ef | grep 'hsql' | wc -l将在Runtime.exec()方法中作为参数传递时返回3。现在我已经知道分叉进程的inputstream或errstream不能溢出。否则会导致死锁。

记住这一点我写了这段代码:

import java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStreamReader;  
import java.util.Date;

public class MonitorHsqlJBossRadius {  

    public static void main(String[] args) {  
        String hsqlCmd[] = {"/bin/bash","-c","ps -ef | grep 'hsql' | wc -l "};  
        String jbossCommand[] = {"/bin/sh","-c","ps -ef | grep 'jboss' | wc -l"};  
        String radiusCommand[] = {"/bin/sh","-c","ps -ef | grep 'radius' | wc -l"};  
        String mySqlCommand[] = {"/bin/sh","-c","/etc/init.d/mysqld status"};  
        String line = null;  
        String mobNo = "(obscured)";  
        Process process = null;  
        Runtime runtime = Runtime.getRuntime();  
        BufferedReader reader = null;  
        SendSMS sender = new SendSMS();  
        boolean sendMsgHsql = false;  
        boolean sendMsgJBoss = false;  
        boolean sendMsgRadius = false;  
        int itr = 1;  
        while(true)  
        {  
            try
            {  
                process = runtime.exec(hsqlCmd);  
                reader = new BufferedReader(new InputStreamReader(process.getInputStream()));  
                while((line=reader.readLine())!=null)  
                {  
                    if (!line.equals("3"))  
                        sendMsgHsql = true;  
                }  

                process.waitFor();  
                if (sendMsgHsql)  
                {  
                    //sender.sendSMS("HSQL is not running "+(new Date().toString()), mobNo,1,itr);  
                    System.out.println("HSQL is not running "+itr);  
                }  
                else  
                    System.out.println("HSQL is running "+itr);  

                sendMsgHsql = false;  

                process = runtime.exec(jbossCommand);  
                reader = new BufferedReader(new InputStreamReader(process.getInputStream()));  
                while((line=reader.readLine())!=null)  
                {  
                    if (!line.equals("3"))  
                       sendMsgJBoss = true;  
                }  

                process.waitFor();  
                if (sendMsgJBoss)  
                {  
                    //sender.sendSMS("JBoss is not running "+(new Date().toString()), mobNo,2,itr);  
                    System.out.println("JBoss is not running "+itr);  
                }  
                else  
                    System.out.println("JBoss is running "+itr);  

                sendMsgJBoss = false;  

                process = runtime.exec(radiusCommand);  
                reader = new BufferedReader(new InputStreamReader(process.getInputStream()));  
                while((line=reader.readLine())!=null)  
                {  
                    if(!line.equals("3"))  
                        sendMsgRadius = true;  
                }  

                process.waitFor();  
                if (sendMsgRadius)  
                {  
                    //sender.sendSMS("Radius is not running "+(new Date().toString()), mobNo,3,itr);  
                    System.out.println("Radius is not running "+itr);  
                }  
                else  
                    System.out.println("Radius is running "+itr);  

                sendMsgRadius = false;  
            }   


            catch (IOException e) {  
                e.printStackTrace();  
            }   
            catch (InterruptedException e) {  
                e.printStackTrace();  
            }

            try  
            {  
                System.out.println("\n--------- "+itr+" ------------\n");  
                itr++;  
                Thread.sleep(1000*5);  
            }  
            catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }
    }
}  

我期待的输出如下

HSQL is running/not running 1
JBoss is running/not running 1
MySQL is running/not running 1
-------------------1----------------

HSQL is running/not running 2
JBoss is running/not running 2
MySQL is running/not running 2
-------------------2----------------

依旧......

Howevere我没有得到这样的输出。有时不打印HSQL的状态消息,或者有时不打印JBoss状态消息。有时候我会得到像

这样的输出
------------------1----------------------

打印此状态消息后。所有我想说的是,这似乎是一些竞争条件或一些同步问题。

2 个答案:

答案 0 :(得分:1)

尝试通过解析ps的输出来确定进程是否正在运行通常不是一个好主意。典型的错误是grep processname匹配(至少)两个进程:processname和grep-process本身。

通常的做法是:

  • 启动过程时,将pid写入文件
  • 检查过程时,从文件中读取pid并通过向其发送信号来查看它是否存在

更加强大和优雅的方法是让进程打开一个套接字并检查它是否可用,但在这种情况下,您不希望在服务器中为此添加代码。但是,您要检查的进程已经侦听TCP端口。我会编写试图连接到这个端口的代码(通常是端口80用于jboss,3306用于mysql,9001用于hsql)Radius因使用UDP而有点棘手。您可以尝试执行身份验证,也可以使用特定的radius-server查找特定的特征。

答案 1 :(得分:0)

我不相信您的代码因竞争条件或同步而挂起。我无法访问您的服务器,所以我无法运行您的代码以确保,但我怀疑您正在运行的进程是阻塞的,因为他们正在写入他们的标准错误并且您没有从中读取它。

可以从Runtime.getRuntime().exec()创建的进程的标准错误流中读取,但是必须在单独的线程中读取此流。相反,我建议使用ProcessBuilder。在我看来,ProcessBuilder最显着的好处是它可以将流程的标准错误重定向到与标准输出相同的流中。这意味着您只能读取一个流,并且不需要单独的线程。

我还会注意到你正在打开各种BufferedReader但不关闭它们。我建议你在完成它们后关闭它们。

最后,我建议您不要重复三次相同的代码。应该可以编写一个方法,使命令行作为String数组参数运行,使用ProcessBuilder运行命令行,并返回行3是否是该命令的输出。