FileChannel和RandomAccessFile似乎不起作用

简单来说:使用sqlitejdbc作为后端的swing应用程序。 目前,启动使用相同数据库文件的多个实例没有问题。 应该有。 该文件已被锁定(在应用程序运行时无法将其删除)因此检查应该是微不足道的。 事实certificate不是。

File f = new File("/path/to/file/db.sqlite"); FileChannel channel = new RandomAccessFile(f, "rw").getChannel(); System.out.println(channel.isOpen()); System.out.println(channel.tryLock()); 

结果是

  true sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid] 

无论应用程序是否正在运行。 我错过了这一点吗? TIA。

FileLocks是JVM独有的,而不是单个线程。 因此,如果您在与Swing应用程序相同的进程中运行该代码,您将获得锁定,因为它由JVM共享。

如果您的Swing应用程序没有运行,则没有其他进程争用锁定,因此您可以很好地获取它。

文件系统级锁与其他应用程序交互。 你从FileChannel得到其中一个。 因此,在示例代码中执行的操作将使文件看起来锁定到另一个进程,例如vi。

但是,JVM中的其他Java线程或进程将看不到锁。 关键句是“文件锁代表整个Java虚拟机。它们不适合控制同一虚拟机中多个线程对文件的访问。” 您没有看到锁,因此您在与应用程序相同的JVM中运行sqlitejdbc。

那么问题是你如何看待你的JVM是否已经获得了对文件的锁定(假设你没有控制获取锁的代码)? 我想要的一个建议是尝试获取文件的不同子集的独占锁,例如使用以下代码:

 fc.tryLock(0L, 1L, false) 

如果已经存在锁定,则应该获得OverlappingFileLockException。 这有点hacky但可能会奏效。

你能做一点实验吗? 运行这个程序的两个副本(只是你的代码与睡眠):

 public class Main { public static void main(String [] args) throws Exception { File f = new File("/path/to/file/db.sqlite"); FileChannel channel = new RandomAccessFile(f, "rw").getChannel(); System.out.println(channel.isOpen()); System.out.println(channel.tryLock()); Thread.sleep(60000); } } 

如果这没有锁定,您就知道tryLock()不能在您的OS /驱动器/ JVM上运行。 如果这确实锁定了,那么你的逻辑就会出现其他问题。 请在评论中告知我们结果。