2

有没有办法ps在 Java 中定期运行 Unix 命令(在我的情况下)?我写的循环:

while( this.check )
{
    try 
    {
            ProcessBuilder pb = new ProcessBuilder("ps");
            Process proc;

            System.out.println(" * * Running `ps` * * ");

            byte[] buffer;
            String input;

            proc = pb.start();
            BufferedInputStream osInput = 
                new BufferedInputStream(proc.getInputStream());

            //prints 0 every time after the first
            System.out.println(osInput.available());

            buffer = new byte[osInput.available()];
            osInput.read(buffer);
            input = new String(buffer);
            for( String line : input.split("\n"))
            {
                if( line.equals("") )
                    continue;
                this.handlePS(line);
            }

            proc.destroy();
            try 
            {
                Thread.sleep(10000);
            } 
            catch (InterruptedException ie) 
            {
                ie.printStackTrace();
            }
        } 
        catch (IOException ioe) 
        {
            ioe.printStackTrace();
        }
    }
}

不起作用。它第一次运行得很好,但此后每次输入流都有 0 个字节可用。我会尝试这个watch命令,但是这个 Solaris 盒子没有那个。我不能使用 cron 作业,因为我需要知道 PID 是否存在于 Java 应用程序中。有任何想法吗?

提前致谢。

编辑:不能使用 cron 作业

编辑:结束后我正在制作一个新Thread的相同类型(PS),所以我肯定每次都在制作一个新的 ProcessBuilder。

编辑:我把没有工作的循环放回去了,因为它引起了混乱。

4

3 回答 3

3

我不确定循环在哪里,但每次循环都需要创建一个新Proc对象(因此也是一个新对象)。InputStream否则,您将始终查看第一次调用的结果。javadocs forProcessBuilder表明您不需要每次都创建其中一个。

还可能存在竞争条件,当您调用时输入流尚未准备好available()。在打印结果之前,您应该确保输入流已达到 EOF(这将在 ps 中发生,尽管不会在 top 中发生)。

您也没有正确处理编码,尽管我不知道“ps”的输出是哪种编码(ASCII 之外)。由于“ps”可能是 ASCII,这是相当安全的,但可能不适用于其他命令(以及其他输入流)。

于 2009-06-24T19:00:35.830 回答
1

除了 Kathy 的回答之外,您还应该为每次调用在单独的线程中收集 stdout 和 stderr 。否则进程会阻塞等待你读取这些数据。

有关更多详细信息,请参阅此答案

编辑。您是否正在调用waitFor()来收集任何退出状态?我通常处理这个的方式是执行然后调用waitFor(). 我认为destroy()在这种情况下可能是多余的。

于 2009-06-24T19:06:17.957 回答
1

所以我认为问题在于您在 ps 执行结束之前检查输入流。尝试添加:

proc.waitFor()

在调用 osInput.available() 之前。

以下是我将如何实现它:

    TimerTask task = new TimerTask() {

        private void work() throws Exception {
            System.out.println("Now");
            ProcessBuilder pb = new ProcessBuilder("ps");
            Process p = pb.start();
            p.waitFor();
            BufferedReader reader
                = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                // Process line
                System.out.println(line);
            }
        }

        @Override
        public void run() {
            try {
                work();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    Timer timer = new Timer();
    long period = 5000;
    timer.scheduleAtFixedRate(task, 0, period);
于 2009-06-24T19:21:39.940 回答