在我的一个项目中,我对一个 JRE 中的一个文件进行并发写入访问,并且希望通过首先写入临时文件,然后使用原子移动将该临时文件移动到目标来处理该问题。我不关心写入访问的顺序等,我需要保证的是在任何给定时间单个文件都是可用的。我已经知道 Files.move 等,我的问题是我至少查看了该方法的一个实现,它对实现是否真正保证原子移动产生了一些疑问。请看下面的代码:
OpenJDK 的 GrepCode 上的 Files.move http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/nio/file/Files.java#Files.move%28java.nio.file.Path%2Cjava.nio.file.Path%2Cjava.nio.file.CopyOption%5B%5D%29
1342 FileSystemProvider provider = provider(source);
1343 if (provider(target) == provider) {
1344 // same provider
1345 provider.move(source, target, options);
1346 } else {
1347 // different providers
1348 CopyMoveHelper.moveToForeignTarget(source, target, options);
1349 }
问题是,并非在所有情况下都考虑选项 ATOMIC_MOVE,但源路径和目标路径的位置是唯一重要的事情。这不是我想要的,也不是我理解文档的方式:
如果移动不能作为原子文件系统操作执行,则
抛出 AtomicMoveNotSupportedException。例如,当目标
位置位于不同的 FileStore 上,并且需要复制该文件或目标
位置与该对象的不同提供者相关联。
上面的代码显然违反了该文档,因为它根本不识别 ATOMIC_MOVE 就退回到复制删除策略。在我的情况下,一个例外是完全可以的,因为这样我们服务的托管者可以更改他的设置以仅使用一个支持原子移动的文件系统,因为无论如何这都是我们在系统要求中所期望的。我不想处理的是,仅仅因为实现使用复制删除策略而导致默默失败,这可能会导致目标文件中的数据损坏。因此,根据我的理解,依赖 Files.move 进行原子操作根本不安全,因为如果不支持这些操作,它并不总是失败,但实现可能会退回到复制删除策略。
这种行为是否是实现中的错误,需要提交,或者文档是否允许这种行为,而我理解错误?如果我现在已经知道那里使用了这种可能损坏的实现,那么这有什么区别吗?在这种情况下,我需要自己同步写入访问......