原文提供的是 C++/MFC 互斥體代碼,Java 中無原生互斥體 API,但可通過文件鎖或本地 Socket 端口佔用實現單實例運行。
利用操作系統文件鎖機制,進程退出自動釋放:
public class SingleInstanceLock {
private static FileChannel channel;
private static FileLock lock;
public static boolean tryLock(String lockFilePath) {
try {
File file = new File(lockFilePath);
channel = new RandomAccessFile(file, "rw").getChannel();
lock = channel.tryLock(); // 非阻塞嘗試
if (lock == null) return false; // 已被鎖定
// 添加關閉鉤子釋放(雖然 JVM 退出自動釋放)
Runtime.getRuntime().addShutdownHook(new Thread(() -> release()));
return true;
} catch (IOException e) {
return false;
}
}
private static void release() {
try { if (lock != null) lock.release(); if (channel != null) channel.close(); }
catch (IOException ignored) {}
}
}
// 主程序入口
public static void main(String[] args) {
if (!SingleInstanceLock.tryLock(System.getProperty("java.io.tmpdir") + "/myapp.lock")) {
System.out.println("程序已在運行!");
// 可選:發送激活信號給已有進程(需額外 IPC 機制)
return;
}
// 正常啟動業務邏輯...
}
優點:跨平台、語義清晰、進程崩潰自動釋放。
缺點:網絡文件系統 (NFS) 上鎖行為不可靠。
綁定 localhost 高位端口,佔用成功即獲取鎖:
public class SingleInstanceSocket {
private static ServerSocket serverSocket;
private static final int PORT = 54321; // 固定端口
public static boolean tryLock() {
try {
serverSocket = new ServerSocket(PORT, 1, InetAddress.getByName("127.0.0.1"));
// 保持 ServerSocket 存活直到程序結束
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try { serverSocket.close(); } catch (IOException ignored) {}
}));
return true;
} catch (IOException e) {
return false; // 端口被佔用
}
}
}
優點:極簡、可擴展為進程間通訊(IPC)通道。
缺點:端口衝突風險(建議用 >49151 動態端口)、防火牆可能干擾。
若需將二次啟動的參數傳給主實例、或激活主窗口:
ServerSocket.accept() 循環監聽Platform.runLater(() -> stage.toFront()) JavaFX)createTempFile 刪除檢查法(競態條件不可靠)