2

假设两个(或更多)并发运行的 Java 进程需要检查文件是否存在,如果不存在则创建它,然后在运行过程中可能从该文件中读取。我们希望保护自己免受多个写入器进程相互干扰和/或读取器进程读取文件的不完整或不一致版本的可能性。

我们目前正在做的仲裁这种情况是使用Java NIO FileLocks。一个进程设法在要创建的文件上获取排他锁FileChannel.tryLock()并创建它,而其他并发运行的进程无法获取锁并回退到使用该文件的内存版本进行运行。

然而,锁定给我们的计算场带来了各种问题,因此我们正在探索替代方案。所以我的问题是:有没有办法在不使用文件锁的情况下安全地做到这一点?

例如,进程是否可以在发现文件不存在时写入独立的临时文件,然后在写入临时文件后或多或少“原子地”将临时文件移动到位?在这种情况下,我们可能最终会得到多个写入器进程,但如果从文件中读取的任何进程总是读取一个或另一个版本,而不是两个或多个版本的混合,那将是可以的。但是,我认为并非所有操作系统都保证如果您打开文件以供读取,即使在读取过程中被覆盖,您也会继续从文件的原始版本读取。

我们欢迎所有的建议!

4

1 回答 1

2

假设两个(或更多)并发运行的 Java 进程需要检查文件是否存在,如果不存在则创建它,然后在运行过程中可能从该文件中读取。

我不太了解问题的创建和阅读部分。如果您希望确保您有一个唯一的文件,那么您可以使用new File(...).createNewFile()并检查以确保它返回true. 引用 Javadocs:

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

这将为您提供一个只有该进程(或线程)才能“拥有”的唯一文件。但是,我不确定您打算如何让作者知道要写入哪个文件。

如果您正在谈论创建一个您编写的唯一文件,然后将其移至写入目录以供使用,那么上述内容应该可以工作。完成后,您还需要在写入目录中创建一个唯一名称。

您可以使用以下内容:

private File getUniqueFile(File dir, String prefix) {
    long suffix = System.currentTimeMillis();
    while (true) {
        File file = new File(dir, prefix + suffix);
        // try creating this file, if true then it is unique
        if (file.createNewFile()) {
           return file;
        }
        // someone already has that suffix so ++ and try again
        suffix++;
    }
}

作为替代方案,您还可以使用UUID.randomUUID()或生成唯一名称的东西创建唯一文件名。

于 2013-04-16T20:09:19.270 回答