使用JAVA中的PIDvalidation进程是否正在运行

我目前正在用JAVA构build一个只能执行一次的应用程序。 所以我正在使用一个locking文件,在其中我写入当前执行的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 */ } 

我试图find有关这个问题的文档,但我没有设法find有用的东西。

非常感谢你。

在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

以下代码确定具有指定pid的进程是否正在运行。 它在Windows 7和Ubuntu 13上进行了测试。在Windows上,它使用apache commons-exec运行tasklist,并根据它们的退出代码确定是否找到指定的pid。 它克服了这样一个事实,即任务列表总是通过将结果输送到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; } 

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

布尔方法isStillAllive(…)将获取进程标识号(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; } }