There are other questions on SO that are very similar to this, but none that completely solves my problem:
I have a Java program that I'd like to run on a schedule, and I don't want multiple copies to be running at once. So, I'm using javax.nio.channels.FileLock
like this (simplified):
File fileToLock = new File("lockfile");
RandomAccessFile raf = new RandomAccessFile(fileToLock, "rw");
FileLock lock = raf.getChannel().lock();
// File is locked, do my work
lock.release();
raf.close();
This works great, except that the lock file sticks around after termination. If I add a delete at the end of the program:
fileToLock.delete();
The file gets deleted before the program terminates. Great.
Except, when running two copies of the program at the same time, they both open the lock file as a random-access file which means they are both pointing to the same directory entry, and when the process that holds the lock deletes the file and releases the lock, the second process then has a deleted file upon which it has a lock.
That means that another instance of the program can start-up because requesting a RandomAccessFile
called "lockfile" will create a new file and lock it, even when the old lockfile is still "locked" by another process. Here's a quick description of the order of events:
- Process A launches, creates
lockfile
(inode 123) and locks it - Process B lanuches, opens "lockfile", requests a lock, and blocks waiting for the lock
- Process A completes, deletes inode 123, and releases the lock on it
- Process B acquires the lock on inode 123 (still valid because inode 123 has a file descriptor owned by a live process) and continues
- Process C launches, creates
lockfile
(inode 124) and locks it
At this point, I've got two processes running at once, which was the thing I wanted to avoid.
I've also tried File.renameTo
but of course that has the same problem: the name of the file is irrelevant once it's been opened because the FileChannel
is pointing to a file descriptor and not a "name" on the filesystem.
My only option seems to be to leave the lock file in place even when it's not being actively used as a lock file. Are there other solutions to this problem?