Java's FileLock allows to lock twice

78 views Asked by At

In Java on Ubuntu, I'm using a FileLock to lock a file. The problem regularly happens on a server that runs on Debian. To make it easily reproducible, I wrote a minimal sample application (see below). As you can see, the application first locks a lock file, and then once the lock was retrieved successfully, it creates a test file. It will delete the test file again before the lock is released. Because of the locking, it should never happen that the test file already exists immediately after successfully receiving the lock. However, when running this application twice (simultaneously), and due to the System.gc() call (which I needed to add to reproduce the server problem), the lock seems to be granted twice. This does not make sense.

I tested the code using an old version of Java (OpenJDK 11) and a new version of Java (OpenJDK 21). They deliver the same result.

See the following code:

public static void main(String[] args) throws Exception {
    Random rand = new Random();
    
    while (true) {
        File lockFile = new File("/tmp/lock-file");
        if (!lockFile.exists()) {
            lockFile.createNewFile();
        }
        
        RandomAccessFile rac = new RandomAccessFile(lockFile, "rw");
        FileChannel channel = rac.getChannel();
        FileLock lock = channel.tryLock();

        if (lock == null) {
            System.out.println("Could not get lock");
        } else {
            System.out.println("Got lock");

            File testFile = new File("/tmp/test-file");
            if (testFile.exists()) {
                throw new Exception("FILE MUST NOT EXIST. LOCK PROBLEM.");
            }
            
            testFile.createNewFile();
            
            // This helped to reproduce the server problem
            System.gc();
            
            Thread.sleep(rand.nextInt(4));
            
            testFile.delete();
            
            if (!lock.isValid()) {
                throw new Exception("Lock is not valid anymore!");
            }
            
            lock.release();
            channel.close();
            rac.close();
        }
        
        Thread.sleep(rand.nextInt(4));
    }
}

Output of the first instance of the application:

java -jar test.jar
Got lock
Got lock
Got lock

Output of the second instance of the application:

java -jar test.jar
Got lock
Got lock
Could not get lock
Got lock
Exception in thread "main" java.lang.Exception: FILE MUST NOT EXIST. LOCK PROBLEM.
    at test.Test.main(Test.java:44)

I tried to use file locking in Java and I would have expected that a file cannot be locked twice by two processes. However, it seems that Java allows to lock files twice and that is a problem for me. Any idea what's wrong?

1

There are 1 answers

3
delx On

I found a solution myself. I needed to add the following code inside the code block of the if-clause if (lock == null):

channel.close();
rac.close();

With that change, it works flawlessly. I hope this answer will save same hours as it would have for me!