无法使用java.nio.channels.FileLock在Linux上locking文件

我正在创build一个Java应用程序,我只想运行一个实例。 为此,我创build了一个文件,并在运行应用程序时获得了一个锁。

我有以下代码在Windows上工作,但在Linux上失败:一旦我获得一个锁而不解锁它,我可以得到另一个锁。

import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; public class MyApp { private static File f; private static FileChannel channel; private static FileLock lock; public static void main(String[] args) { try { f = new File("RingOnRequest.lock"); // Check if the lock exist if (f.exists()) { // if exist try to delete it f.delete(); } // Try to get the lock channel = new RandomAccessFile(f, "rw").getChannel(); lock = channel.tryLock(); if(lock == null) { // File is lock by other application channel.close(); throw new RuntimeException("Only 1 instance of MyApp can run."); } // Add shutdown hook to release lock when application shutdown ShutdownHook shutdownHook = new ShutdownHook(); Runtime.getRuntime().addShutdownHook(shutdownHook); //Your application tasks here.. System.out.println("Running"); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } catch(IOException e) { throw new RuntimeException("Could not start process.", e); } } public static void unlockFile() { // release and delete file lock try { if(lock != null) { lock.release(); channel.close(); f.delete(); } } catch(IOException e) { e.printStackTrace(); } } static class ShutdownHook extends Thread { public void run() { unlockFile(); } } } 

我使用了与你同样的示例,并在Mac OS X上遇到了同样的问题。似乎文件锁定并不妨碍POSIX系统上的文件删除。 你的应用程序仍然有某种类型的文件处理,直到你解锁它。 所以考虑使用带有PID的锁定文件(或文件内)。

每次运行时都会删除锁定文件,所以只有一个进程可以锁定它。

当你使用FileLock ,它是纯粹的建议 –获取对文件的锁定可能不会阻止你做任何事情……即使在另一个进程已经获得了锁定的情况下,读取,写入和删除文件也是可能的。 有时候,在特定的平台上,锁可能比这更多,但是这种行为是不确定的,在类文档中依赖更多的是保证失败。

咨询锁只是一个信号,其他进程都可以看到, 如果你不仅仅依赖它,你的程序在其他平台上运行时将会中断。

为什么你会删除锁定文件呢? 锁定文件就像一个布尔标志,对系统上的每个进程都是可见的。 设计你的协议使用它,你将有一个可靠的,跨平台的锁定机制。

为什么不把PID保存到一个文件中,而不是锁定文件,确认是否有一个具有该ID的进程。 如果有,并且是您的应用程序的一个实例,您知道它已经在运行。

套接字也可能是个好主意,因为你可以使用它来与正在运行的实例进行通信。

编辑:

另外,从FileLock的javadoc :

锁是否实际上阻止另一个程序访问锁定区域的内容是依赖于系统的,因此是未指定的。

使用mkdir 。 在UNIX系统上,这是一个原子操作 – 如果成功创建一个新目录,它将成功,否则将失败。

例:

 File lockFile = new File("/path/to/lockdir"); boolean hasLock = lockFile.mkdir(); if (!hasLock) { throw new IOException("could not get lock"); } // do stuff lockFile.delete(); 

我在Windows和Linux上测试了它。 工作正常。 当应用程序正常关闭时,锁定文件被自动删除。 因此,当您重新启动应用程序时,您不必担心锁定文件停留在那里。 只需注释以下几行:

 if (f.exists()) { // if exist try to delete it f.delete(); } 

但是,您可能需要考虑如果应用程序崩溃并且不以正常方式关闭会发生什么情况。