在Windows/Linux中检查进程是否正在运行

9
我有一个进程。
Runtime rt = Runtime.getRuntime() ;
Process p = rt.exec(filebase+port+"/hlds.exe +ip "+ip+" +maxplayers "+players+ " -game cstrike -console +port "+port+" -nojoy -noipx -heapsize 250000 +map de_dust2 +servercfgfile server.cfg +lservercfgfile +mapcyclefile mapcycle.txt +motdfile motd.txt +logsdir logs -zone 2048",null,  new File(filebase+port)) ;

我希望能够监控这个进程,无论它是否正在运行或已经崩溃,在崩溃的情况下需要重新启动它。该进程可以有多个实例,具体数量取决于端口。

我能在Linux和Windows上跟踪这个进程吗?我读了一些相关文章,但是这个情况有点不同,因为它涉及到多个出现的实例,并且必须仅检查特定的进程。

7个回答

25

1
我知道控制流程不应该使用异常,但Java并没有给我们更好的选择。 - AlikElzin-kilaka

3
您可以使用 p.waitFor() 方法来使执行该语句的线程等待进程完成。然后,您可以在进程退出时执行一些清理/重启逻辑。但是,如果进程挂起而不是退出,我不确定这种方法是否可行,但可以尝试。顺便说一下,如果您要在生产环境中执行此操作,我建议使用 Java Service Wrappersupervisord

在这种情况下,我应该每次启动新进程时创建一个新线程吗?并且在同一线程上保持轮询? - Varun

2

2
虽然这理论上回答了问题,但最好在此处包含答案的基本部分,并提供参考链接。 - Bhargav Rao

1

对于Java 8之前的代码,我使用反射并回退到捕获IllegalThreadStateException。反射仅适用于ProcessImpl实例,但通常情况下ProcessBuilder返回的就是这种情况。

    public static boolean isProcessIsAlive(@Nullable Process process) {
    if (process == null) {
        return false;
    }
    // XXX replace with Process.isAlive() in Java 8
    try {
        Field field;
        field = process.getClass().getDeclaredField("handle");
        field.setAccessible(true);
        long handle = (long) field.get(process);
        field = process.getClass().getDeclaredField("STILL_ACTIVE");
        field.setAccessible(true);
        int stillActive = (int) field.get(process);
        Method method;
        method = process.getClass().getDeclaredMethod("getExitCodeProcess", long.class);
        method.setAccessible(true);
        int exitCode = (int) method.invoke(process, handle);
        return exitCode == stillActive;
    } catch (Exception e) {
        // Reflection failed, use the backup solution
    }
    try {
        process.exitValue();
        return false;
    } catch (IllegalThreadStateException e) {
        return true;
    }
}

0
public class ProcessEndNotifier extends Thread
{
    Process process;
    MyClass classThatNeedsToBeNotified;

    public ProcessEndNotifier(MyClass classThatNeedsToBeNotified, Process process)
    {
        this.process = process;
        this.classThatNeedsToBeNotified = classThatNeedsToBeNotified;
    }

    @Override
    public void run()
    {
        try {
            process.waitFor();
        }
        catch (InterruptedException e) {
            classThatNeedsToBeNotified.processEnded();
        }
        classThatNeedsToBeNotified.processEnded();
    }
}

现在你可以知道进程是否正在运行,就像这样:
public class MyClass
{
    boolean isProcessRunning;       

    public static void main(String[]args)
    {
        Process process = Runtime.getRuntime().exec("foo -bar");
        isProcessRunning = true;
        new ProcessEndNotifier(this, process).run();
    }

    public void processEnded()
    {
        isProcessRunning = false;
        // Or just do stuff here!
    }
}

0

Java 5 及其以后版本可以使用 java.util.concurrent.Future 来处理这个问题。

Future 表示异步计算的结果。提供了方法来检查计算是否完成,等待其完成并检索计算结果。当计算完成时,只能使用 get 方法检索结果,如果必要,会阻塞直到准备好。取消操作由 cancel 方法执行。还提供了其他方法来确定任务是正常完成还是被取消。一旦计算完成,计算就无法被取消。如果您想为了可取消性而使用 Future,但不提供可用的结果,则可以声明形式为 Future 的类型,并将 null 作为底层任务的结果返回。


1
不理解这个方法...请给一个清晰的解释 :) - Varun
在Java 5中,新增了一个非常强大的包java.util.concurrent。它通过提供能够高效且线程安全地处理不同用例的类,使得管理子进程变得更加容易。如果您需要实现生产者/消费者、阻塞队列或定时任务,大部分繁重的工作都已经完成。Future类用于跟踪线程的状态,甚至可以在其存在时获取返回值。使用这个包,特别是使用Future,似乎可以为您节省很多工作。 - dj_segfault
1
ProcessFuture之间有什么联系? - AlikElzin-kilaka

0
在Java 9中,您可以使用isAlive()方法来检查进程是否仍在运行,如下所示:
Runtime rt = Runtime.getRuntime() ;
Process p = rt.exec(filebase+port+"/hlds.exe +ip "+ip+" +maxplayers "+players+ " -game cstrike -console +port "+port+" -nojoy -noipx -heapsize 250000 +map de_dust2 +servercfgfile server.cfg +lservercfgfile +mapcyclefile mapcycle.txt +motdfile motd.txt +logsdir logs -zone 2048",null,  new File(filebase+port)) ;
boolean isRunning = p.toHandle.isAlive();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接