Java中的文件系统锁定



当从文件中读取行并处理它们时,我在某些代码中使用了文件系统锁。这是因为我的体系结构有不止一个应用程序服务器;我只想要一台服务器来处理每一行,以避免数据重复。

我在助手方法中创建了一个DTO。对象中填充了锁的详细信息,这些信息可以由helper方法返回,随后可以查询以查看锁是否成功。如果是,则可以处理文件中的行。

通常,如果两个服务器同时尝试处理文件中的行,其中一个服务器会抛出异常,因为文件已被另一个服务器锁定。如果发生这种情况,我的代码会捕获异常,然后移到文件中的下一行。

锁定实现如下:

String filename = <Unique identifier of record being processed>;
File lockfile = new File(System.getProperty("java.io.tmpdir"), filename);
RandomAccessFile randomAccessfile = new RandomAccessFile(lockfile, "rw");
FileChannel fileChannel = randomAccessfile.getChannel();
FileLockDTO fileLockDTO = new FileLockDTO();
fileLockDTO.setLockedfile(lockfile);
fileLockDTO.setRandomAccessfile(randomAccessfile);
fileLockDTO.setFileLock(fileChannel.tryLock()); 

在绝大多数情况下,代码运行良好。然而,在极少数情况下,会出现重复的记录,这表明存在一种边缘情况,即多个应用程序服务器似乎可以在完全相同的时间创建锁。

我看了很久;仔细研究代码并尝试了大量测试,但无法确定这将如何发生。只是想知道有没有人有什么想法?

提前感谢您的帮助。

来自FileLock javadocs:

锁定是否真的阻止另一个程序访问锁定区域的内容取决于系统,因此未指定。一些系统的本机文件锁定功能只是建议性的,这意味着程序必须协同遵守已知的锁定协议,以确保数据的完整性。

FileChannel.tryLock()的javadocs:(重点是我的(一个OverlappingFileLockException被抛出

如果与请求区域重叠的锁已被此Java虚拟机持有,或者另一个线程已在此方法中被阻止并试图锁定重叠区域

以下是应用程序的一个简单失败场景:

  1. 服务器A查询资源1是否存在锁=>返回false
  2. 服务器B查询资源1是否存在锁=>返回false
  3. 服务器A运行上面代码片段中的第1-4行并成功
  4. 服务器B运行上面代码片段中的第1-4行并成功(什么会阻止它?(
  5. 服务器A创建DTO
  6. 服务器B创建DTO(根据操作系统的不同,对tryLock()的调用可能不会停止任何操作(
  7. 服务器A处理"锁定"记录
  8. 服务器B处理"锁定"记录

您必须依赖FileLockDTO.setFileLock((内部的null检查,或者无论您在哪里,如果您确实拥有它的话。所有这些对我来说似乎太复杂了。我只会锁定你正在阅读的实际文件的实际行,而不是引入这些辅助锁定文件。然后,如果你遇到一个现有的锁,你知道要跳过那一行。或者使用一种数据结构,该数据结构能够只传递每一行一次并消除整个问题,例如某种MQ或数据库。

EDIT否决者和/或FileLocks不能跨JVM或流程工作的理论的拥护者需要阅读文档。

最新更新