我目前正在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
*/
}
我试图找到关于这个主题的文档,但我找不到任何有用的东西。
非常感谢。
答案 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
的包装器或文件锁定系统调用,例如实现此方案所需的flock
,lockf
和fcntl
。
答案 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>
命令并检查退出值。