I provide two answers, one for 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应用程序不会在同一时间运行两次,因为如果程序崩溃或永久挂起并被杀死,那么锁定将处于不一致的状态,甚至可能在重新启动后仍然存在,这将导致问题,因为程序如何分别识别仍在运行的程序和已崩溃并留下锁定文件的程序?