我提供了两个答案,一个针对 Linux:
如果程序已经在运行,不要运行它,把它放在一个名为 Main.java 的文件中
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
class JustOneLock {
FileLock lock;
FileChannel channel;
public boolean isAppActive() throws Exception{
File file = new File(System.getProperty("user.home"),
"FireZeMissiles1111" + ".tmp");
channel = new RandomAccessFile(file, "rw").getChannel();
lock = channel.tryLock();
if (lock == null) {
return true;
}
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
lock.release();
channel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
return false;
}
}
public class Main {
public static void main(String[] args)throws Exception {
JustOneLock u = new JustOneLock();
if (u.isAppActive()) {
System.out.println("Already active, stop!");
System.exit(1);
}
else {
System.out.println("NOT active... Do hard work for 5 seconds.");
try{Thread.sleep(5000);}catch(Exception e){}
}
}
}
编译并运行它。然后打开一个新终端并尝试在另一个正在运行时再次运行它,但它不会。
Windows的另一个答案
如果该程序已在当前系统上运行,则该程序将不允许自己运行。这仅适用于 Windows 系统。
import java.io.*;
import java.util.prefs.Preferences;
public class JavaApplication3 {
public static void main(String[] args){
if(isRunning()){
System.out.println("Two instances of this program cannot " +
"be running at the same time. Exiting now");
}
else{
onStart();
epicHeavyWorkGoesHere();
onFinish();
}
}
public static void epicHeavyWorkGoesHere(){
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {}
}
public static void onStart(){
Preferences prefs = Preferences.systemRoot().node("JavaApplication3");
prefs.put("RUNNINGPID", getCurrentPID());
}
public static void onFinish(){
Preferences prefs = Preferences.systemRoot().node("JavaApplication3");
prefs.put("RUNNINGPID", "");
}
public static boolean isRunning(){
Preferences prefs = Preferences.systemRoot().node("JavaApplication3");
if (prefs.get("RUNNINGPID", null) == null || prefs.get("RUNNINGPID", null).equals(""))
return false;
if (isProcessIdRunningOnWindows(Integer.parseInt(prefs.get("RUNNINGPID", null))))
return true;
return false;
}
public static String getCurrentPID(){
//This function is designed to get the PID from the windows system, it may
//not work for Linux or Mac. You'll have to acquire a suitable getCurrentPID function
try{
java.lang.management.RuntimeMXBean runtime = java.lang.management.ManagementFactory.getRuntimeMXBean();
java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
jvm.setAccessible(true);
sun.management.VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
java.lang.reflect.Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId");
pid_method.setAccessible(true);
return pid_method.invoke(mgmt) + "";
}
catch(Exception e){
throw new RuntimeException("Cannot get the current PID");
}
}
public static boolean isProcessIdRunningOnWindows(int pid){
//This Function only works for windows, if you want it to work on linux
//you will have to go find a replacement method that takes the processID
//as a parameter and spits out a true/false if it is running on the system.
try {
Runtime runtime = Runtime.getRuntime();
String cmds[] = {"cmd", "/c", "tasklist /FI \"PID eq " + pid + "\""};
Process proc = runtime.exec(cmds);
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String line;
while ((line = bufferedreader.readLine()) != null) {
if (line.contains(" " + pid + " ")){
return true;
}
}
return false;
}
catch (Exception ex) {
throw new RuntimeException("Cannot run the tasklist command to query if a pid is running or not");
}
}
}
上述代码的策略是保留上次运行的 PID,如果发现该 PID 在系统上运行,则不要启动。如果完成,请重置。
首选项存储在 Windows 注册表中HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs
我建议不要使用文件锁定来确保 java 应用程序不会同时运行两次,因为如果程序崩溃或永远挂起并被杀死,那么锁就会处于不一致的状态,甚至可能在重启后仍然存在会导致问题,因为程序如何知道仍在运行的程序与已崩溃并保持锁定文件锁定的程序之间的区别?