当锁定文件的另一个 FileChannnel 关闭时,文件的独占锁降级

Exclusive lock on file is downgraded, when another FileChannnel for the locked file is closed

我为该文件获取了独占 FileLock,但是当我为该文件创建另一个 RandomAccessFile/FileChannel 并关闭它时,FileLock 被降级,我可以从另一个进程为该文件获取 FileLock。

遵循更能描述情况的可重现测试

final String path = "/tmp/test.lck";
int sleep = 20_000;

final File dbFile = new File(path);
RandomAccessFile raf = new RandomAccessFile(dbFile, "rw");
final FileLock envLock = raf.getChannel().tryLock(0, 1, false);
System.out.println("Lock acquired " + envLock);

//WE ACQUIRE THE LOCK
//CHECK WITH LSOF you will see
//lsof test.lck
//COMMAND  PID      USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
//java    5088     fefe    4uw  REG  253,2        0 8128854 test.lck

//FILE IS PROPERLY LOCKED, YOU CANNOT OBTAIN LOCK FROM ANOTHER PROCESS !!!! 
//you can run this same program from another terminal and you will not be able to get the lock , tryLock method will return null

System.out.println("going to sleep  " + sleep);
Thread.sleep(sleep);
System.out.println("after sleep  " + sleep);

final File dbFile2 = new File(path);
RandomAccessFile raf2 = new RandomAccessFile(dbFile2, "rw");
raf2.close();    
System.out.println("channel released and closed");

//AFTER THE CHANNEL IS CLOSED, YOU CAN OBTAIN LOCK FROM ANOTHER PROCESSS !!!! <--- HERE IS THE PROBLEM
//you can run this same program from another terminal and you will be able to get lock

//WE CLOSE THE CHANNEL
//CHECK WITH LSOF you will see
//YOU CHAN SEE THE FD CHANGE FROM uw to u
//    COMMAND  PID      USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
//    java    5088      fefe    4u  REG  253,2        0 8128854 test.lck


System.out.println("going to sleep  " + sleep);
Thread.sleep(5 * sleep);
System.out.println("after sleep  " + sleep);

问题是,在我为我拥有 FileLock 的相同文件路径创建 RandomAccessFile 之后,当我关闭 RandomAccessFile 时,我可以从另一个进程获取对文件的锁定。 我认为这是一种奇怪的行为,要么是错误,要么是我遗漏了一些明显的东西。如何正确锁定文件,在随后为同一文件创建 RandomAccessFile 后不会释放锁定(例如 当我想检查我是否持有锁等...)。我已经用 JDK8 和 JDK11 测试过它,并且行为相同。我的文件系统是 xfs

我无法在 Windows 上重现。

来自the Javadoc of FileLock

File locks are held on behalf of the entire Java virtual machine.

This file-locking API is intended to map directly to the native locking facility of the underlying operating system. Thus the locks held on a file should be visible to all programs that have access to the file, regardless of the language in which those programs are written.

On some systems, closing a channel releases all locks held by the Java virtual machine on the underlying file regardless of whether the locks were acquired via that channel or via another channel open on the same file. It is strongly recommended that, within a program, a unique channel be used to acquire all locks on any given file.