如何最好地在 Java 集群中锁定文件

How best to file lock in Java cluster

我在 JBoss 上有一个服务器集群 运行。我需要以安全的方式更新文件。具体来说,我需要

  1. 锁定文件 A -- 如果它已经被锁定,则以一种安全的方式进行阻塞,这样如果 JVM 突然死机,就不会有悬空锁。超时 30 秒就可以了。
  2. 读取文件A
  3. 更改内容
  4. 将文件写入临时名称A.tmp
  5. 删除原文件A
  6. 将 A.tmp 重命名为正确的名称 A
  7. 解锁文件A

当我查看 java.nio.FileLock 时,它似乎与 InputStream 相关联。我真的只需要锁定一个抽象名称。我不需要锁定文件的一部分。如果这是最佳选择,我可以为此创建一个锁定文件(与数据文件分开)。但是我的问题的要点是我需要在读取之前获取锁,然后在更新文件后释放锁。请注意,我以某种方式更新文件以确保我在文件系统上永远不会有部分写入的文件。我需要写入整个文件,然后在写入后重命名它,以确保拥有该名称的任何文件都具有完整的内容集,并且如果进程在写入过程中死亡,它会留下一个可以轻松清理的临时文件稍后补上。

java.nio.FileLock真的适合这种用途吗?还是我应该看看别的东西?

这是我最后做的。对于每个名为 "XXX" 的文件,我使用一个名为 "XXX#LOCK"

的零长度锁定文件
  1. 我锁定它以使用 RandomAccessFile 进行更新。

  2. 当这个锁定文件被锁定时,我操作了有问题的实际文件:读取原始文件、流式传输到临时文件、删除原始文件以及重命名临时文件等。

  3. 我解锁了锁文件

锁定密码:

    File lockFile = new File(target.getParent(), target.getName() + "#LOCK");
    lockAccessFile = new RandomAccessFile(lockFile, "rw");
    FileChannel lockChannel = lockAccessFile.getChannel();
    lock = lockChannel.lock();

解锁码:

    if (lock != null) {
        lock.release();
        lock = null;
    }
    if (lockAccessFile != null) {
        lockAccessFile.close();
        lockAccessFile = null;
    }

我将其包装在一个 class 中,使锁定和解锁与原始文件的读取或写入一起进行。可以看到,locklockAccessFile是成员变量。

我从来没有向锁定文件写入任何内容,但它们存在于文件夹中。由于我有少量文件要以这种方式管理(其中 6 个),我只是将 LOCK 文件留在那里,因为它很丑陋,但无害,开销。

这适用于跨多主机集群的我的代码,因为我的代码是唯一操纵这些文件的东西。最大的问题是,如果其他一些代码在不知道这个约定的情况下开始操作文件,就会导致问题。我还没有找到任何证据表明有一个标准的方法来处理这个问题,该方法将由 OS 强制执行,同时由 Java 支持。如果你知道任何,请告诉我。