使用JAVA中的PID验证进程是否正在运行

时间:2014-01-30 15:36:40

标签: java linux windows

我目前正在JAVA中构建一个只能执行一次的应用程序。所以我目前正在使用一个锁文件,我在其中写入当前执行的PID。

因此,每当此应用程序启动时,它将打开文件(如果存在)并尝试检测文件中写入的PID是否实际正在运行。

这可以防止我的应用在解锁文件之前崩溃的问题。

我需要在Windows(XP,7或8)和linux上工作(所有用户都使用基于debian的发行版)。

这里有一些代码可以让您更好地了解我想要做的事情:

//get the PID from the file
int pidValue = new FileReader(file).read();

//get the OS type
String os = System.getProperty("os.name").toLowerCase();

//Check PID depending of OS type
if( os.contains("nux") || os.contains("nix") ){
/*
 * Check PID on Linux/Unix
*/
} else if ( os.contains("win") ) {
/*
 * Check PID on Windows
 */
}

我试图找到关于这个主题的文档,但我找不到任何有用的东西。

非常感谢。

4 个答案:

答案 0 :(得分:4)

以下代码确定具有指定pid的进程是否正在运行。它在Windows 7和Ubuntu 13上进行了测试。在Windows上,它使用apache commons-exec来运行任务列表,并根据退出代码确定是否找到了指定的pid。它克服了tasklist通过将结果传递给findstr来返回0的事实。在linux上它使用ps来做同样的事情。它还会抑制子进程的stdout日志记录。

public static boolean isProcessRunning(int pid, int timeout, TimeUnit timeunit) throws java.io.IOException {
    String line;
    if (OS.isFamilyWindows()) {
        //tasklist exit code is always 0. Parse output
        //findstr exit code 0 if found pid, 1 if it doesn't
        line = "cmd /c \"tasklist /FI \"PID eq " + pid + "\" | findstr " + pid + "\"";
    }
    else {
        //ps exit code 0 if process exists, 1 if it doesn't
        line = "ps -p " + pid;
            //`-p` is POSIX/BSD-compliant, `--pid` isn't<ref>https://github.com/apache/storm/pull/296#discussion_r20535744</ref>
    }
    CommandLine cmdLine = CommandLine.parse(line);
    DefaultExecutor executor = new DefaultExecutor();
    // disable logging of stdout/strderr
    executor.setStreamHandler(new PumpStreamHandler(null, null, null));
    // disable exception for valid exit values
    executor.setExitValues(new int[]{0, 1});
    // set timer for zombie process
    ExecuteWatchdog timeoutWatchdog = new ExecuteWatchdog(timeunit.toMillis(timeout));
    executor.setWatchdog(timeoutWatchdog);
    int exitValue = executor.execute(cmdLine);
    // 0 is the default exit code which means the process exists
    return exitValue == 0;
}

答案 1 :(得分:2)

在posix系统上,查询pid是否正在运行的典型方法是向其发送空信号,例如kill(pid, 0)。如果呼叫成功,则该过程存在;如果它返回ESRCH则不会。这自然会受到不可避免的竞争条件的影响,实际上比实际情况要少得多。不太统一的方法是读取/ proc文件系统(如果操作系统有一个),这是更多的工作,相同的事情,并仍然受到相同的竞争条件。

请注意,pid lockfile技术可以是双层的。也就是说,正在运行的进程会创建文件,锁定它并写入其pid。它在运行期间保持锁定,因此这几乎消除了上述查询进程是否正在运行的需要,因为如果进程崩溃,即使文件仍然存在,文件锁也会自动释放。逻辑是这样的:

if file exists
   if can get lock
       prev instance died unnaturally
       continue with this new process
   else
       instance already running
else
   good to go, continue with new process

这种技术也有竞争条件。

我不记得有足够的Java来说明它是否有kill的包装器或文件锁定系统调用,例如实现此方案所需的flocklockffcntl

答案 2 :(得分:1)

请参阅下面的准备复制/粘贴示例。

布尔方法isStillAllive(...)将获取进程ID号(pid)作为参数。方法调用非常通用,旨在包装设备相关逻辑,以解决Windows / linux / unix等操作系统上的相同问题。

public boolean isStillAllive(String pidStr) {
    String OS = System.getProperty("os.name").toLowerCase();
    String command = null;
    if (OS.indexOf("win") >= 0) {
        log.debug("Check alive Windows mode. Pid: [{}]", pidStr);
        command = "cmd /c tasklist /FI \"PID eq " + pidStr + "\"";            
    } else if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0) {
        log.debug("Check alive Linux/Unix mode. Pid: [{}]", pidStr);
        command = "ps -p " + pidStr;            
    } else {
        log.warn("Unsuported OS: Check alive for Pid: [{}] return false", pidStr);
        return false;
    }
    return isProcessIdRunning(pidStr, command); // call generic implementation
}

对系统的实际调用委托给isProcessIdRunning()。此方法将以通用方式调用预先形成的系统相关命令,并且逐行消耗和解析从系统获得的结果。如果至少有一个响应行包含pid而不是我们将其解释为成功。

private boolean isProcessIdRunning(String pid, String command) {
    log.debug("Command [{}]",command );
    try {
        Runtime rt = Runtime.getRuntime();
        Process pr = rt.exec(command);

        InputStreamReader isReader = new InputStreamReader(pr.getInputStream());
        BufferedReader bReader = new BufferedReader(isReader);
        String strLine = null;
        while ((strLine= bReader.readLine()) != null) {
            if (strLine.contains(" " + pid + " ")) {
                return true;
            }
        }

        return false;
    } catch (Exception ex) {
        log.warn("Got exception using system command [{}].", command, ex);
        return true;
    }
}

答案 3 :(得分:0)

我知道自从提出这个问题已经很长时间了,但我有点努力检查特定的 pid 是否还活着或没有使用 java 所以这是我的解决方案:

private boolean isServiceRunnign(String servicePid) throws IOException {

    try {
        System.out.println("-- checking for services --");
        System.out.println("--" + System.currentTimeMillis() + "--");

        Process p = Runtime.getRuntime().exec("ps -p " + servicePid);
        System.out.println("Command : "+ "ps -p " + servicePid);

        BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String s = "";
        while ((s = br.readLine()) != null) {
            System.out.println("Bash outputs : " + s);
        }
        br.close();
        p.waitFor();
        // printing out exitValue for debug purposes.
        System.out.println("Exit: " + p.exitValue());
        if (p.exitValue() == 0) {
            System.out.println("-- " + servicePid + " found --");
            return true;
        }

        p.destroy();

        System.out.println("-- " + servicePid + " not found --");
        return false;
    } catch (Exception e) {
        System.out.println("-- " + servicePid + " not found --");
        System.out.println("Exception : " + e.toString());
        return false;
    }
}

*请注意,这仅适用于 linux。

它基本上运行:

ps -p <pid>

命令并检查退出值。