防止使用者重複啟動同一 Java 應用程式(如桌面客戶端、代理服務),需在啟動早期檢測是否已有實例運行,若是則提示並退出。
FileChannel.tryLock() 嘗試獲取**獨佔鎖**。null),表示另一進程已持有鎖 → 程式正在運行。/usr/temp/(類 Unix),確保跨使用者隔離與寫入權限。
private static boolean isRunning() {
boolean running = false;
try {
String osName = System.getProperty("os.name");
String path;
if (osName.contains("Windows")) {
path = System.getProperty("user.home") + File.separator;
} else {
path = "/usr/temp/";
}
File dir = new File(path);
if (!dir.exists()) dir.mkdirs();
String lockFile = path + "sms.lock"; // 應用唯一標識
RandomAccessFile raf = new RandomAccessFile(lockFile, "rw");
FileChannel channel = raf.getChannel();
FileLock lock = channel.tryLock(); // 非阻塞嘗試
if (lock == null) {
System.out.println("程式已在運行中。");
running = true;
}
// 註意:此處為示範簡化,實際應將 raf/channel/lock 保持為類成員,
// 直到程式正常退出,防止被 GC 關閉導致鎖提前釋放。
} catch (IOException e) {
e.printStackTrace();
}
return running;
}
// 正確模式:主類持有鎖引用
public class App {
private static FileChannel lockChannel;
private static FileLock appLock;
public static void main(String[] args) {
if (acquireLock()) {
try { runApplication(); }
finally { releaseLock(); }
}
}
private static boolean acquireLock() { /* tryLock 並保存 channel/lock */ }
private static void releaseLock() { /* lock.release(); channel.close(); */ }
}
user.home 通常為 C:\Users\Name,有寫入權限。/tmp 或 /var/lock 更標準,/usr/temp 可能不存在或需 root 權限。建議使用 System.getProperty("java.io.tmpdir")。使用應用唯一標識(如 com.myapp.Main.lock),避免不同應用衝突。
| 方案 | 優點 | 缺點 |
|---|---|---|
| 檔案鎖 (FileLock) | 跨平台、進程級、自動清理 | 網路檔案系統 (NFS/SMB) 上行為不可靠 |
| Socket 端口佔用 | 簡單、網路可檢測 | 端口衝突風險、防火牆干擾 |
| PID 檔案 | 傳統、易檢查 | 殘留 PID 檔導致誤判、需手動清理 |
| JMX/RMI 註冊 | 管理功能豐富 | 複雜、需額外配置 |
檔案鎖是實現 Java 單例運行檢測的**輕量、跨平台、自清理**首選方案。關鍵在於**持有鎖引用直到程式退出**,並妥善處理跨平台路徑與異常情況。將此檢測置於 main() 最開頭,即可有效防止重複啟動帶來的資源衝突與資料損壞。