Java中文件存在性锁定

12

简短版:为什么不应该使用File.createNewFile()进行文件锁定?或者更具体地说:如果用它来锁定应用程序数据目录,是否会出现问题?


详细信息:

我想通过锁定文件来保护我的应用程序数据目录:如果文件lock存在,则目录被锁定并显示错误消息退出应用程序。如果不存在,它将被创建并且应用程序继续运行。退出时,文件将被删除。

锁定并不经常创建(即性能不是问题),如果在某些错误情况下无法删除文件,则手动删除锁定文件也不是问题。

代码看起来像这样:

File lockFile = new File("lock");
boolean lockCreated = lockFile.createNewFile();
if (lockCreated)
{
    // do stuff
    lockFile.delete();
}
else
{
    System.err.println("Lockfile exists => please retry later");
    // alternative: Wait and retry e.g. 5 times
}

现在我对createNewFile()Javadoc 有点困惑:

原子地创建由该抽象路径名命名的新空文件,仅当尚不存在具有此名称的文件时。检查文件是否存在以及如果不存在则创建文件是一项单个操作,该操作在与可能影响文件的所有其他文件系统活动相对于原子引用。

注意:该方法不应用于文件锁定,因为无法使结果协议可靠工作。应改为使用FileLock设施。

考虑到存在检查和文件创建是原子的,笔记中提到了哪些潜在问题?

来自2007年12月的这篇论坛帖子指出根据 File.delete() 的 Javadoc,存在“显着的平台差异”(尽管我至少在 Java SE 1.4.2之后没有找到这样的说明)。但即使存在这样的差异:它们真的能导致锁定失败(即两个进程同时认为数据目录可用)吗?


注意:我不想要以下任何内容:

  • 锁定文件,以便其他进程无法访问和/或修改它(大多数信息似乎都在讨论此问题)。
  • 确保没有其他进程可以删除锁定。
  • 同步同一JVM的多个线程(尽管我认为我的解决方案应该能够处理这种情况)。

1
取决于“原子”的含义。有应用内的原子操作,也有系统中所有应用程序的原子操作。我猜想这是针对您的应用程序的原子操作,并且无法防止其他并行进程跳入并从您那里抢走文件。 - Marc B
2
你可以放弃使用文件,直接打开一个端口。 - Mark W
1
@MarcB:我原本以为Javadoc的意思是系统范围的原子性:“……与所有其他文件系统活动相对于原子性的单个操作……”。但是你说得很好,我没有想到这一点…… - siegi
@MarkW:好主意。但是除非有人提出不使用文件的理由,否则我会坚持我的基于文件的解决方案。毕竟,这个应用程序并不需要做到完美无缺...;-) - siegi
1
我查看了jgit源代码,他们正在使用相同的方法(LockFile)。正如另一个答案所指出的那样,我想这对于本地文件系统来说是有效的。 - Clemens
2个回答

2
java.nio.file是Java 7中提供的一部分,Files.createFile(…)的Javadoc重复了原子性的承诺,但并未提到与文件锁定有关的信息。
我的推理:
  • 要么较新的方法(来自java.nio.file.Files)受到与旧方法(来自java.io.File)相同(或类似)的问题,而Javadoc只是缺少这些信息……
  • …… 要么更新的方法实际上表现更加可预测和正确。

鉴于java.nio.file中的错误处理和规范已经与自JDK 1.2以来存在的File类相比得到改进,我认为第二种情况是正确的。


我的结论:对于此用例,使用Files.createFile(…)是没有问题的。

在我看来,你的结论可能需要更加清晰明确:你是建议不使用 File.createNewFile() 而仅使用 Files.createFile() 吗?因为后者的 Javadoc 中缺少了这个注释,而且实现方式也完全不同。尽管在两种情况下,调用似乎都以相同的本地调用和相同的参数结束:File: https://github.com/openjdk/jdk/blob/master/src/java.base/windows/native/libjava/WinNTFileSystem_md.c#L569 Files: https://github.com/openjdk/jdk/blob/master/src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.java#L308 - Thorsten Schöning

1
简短回答:Java中可靠的基于文件的锁定不实际。
详细回答:在任何操作系统中,基于文件的锁定问题都归结为文件来自哪种存储系统。几乎所有网络访问的文件系统(NFS、SAMBA等)在文件创建或删除时具有非常不可靠(或至少是不可预测的)同步,这使得一般的Java方式不可取。在某些操作系统中,使用本地文件系统可能会得到所需的结果。但您需要了解底层文件系统及其特性,并小心操作。

3
谢谢你的回答!我理解网络文件系统的行为是不可预测的。对我来说,Java文档听起来相当严格。所以,无论是Java文档正确并保证检查和文件创建是原子性的(至少对于本地文件系统),还是Java文档不正确,并且应该重新制定(例如“尽最大努力”...),都需要进行说明。添加一个非常不具体的注释不应该使之前所做出的保证失效... - siegi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接