views:

40

answers:

1
+1  Q: 

Java file locking

Hi,

I've written the following helper class that should allow me to get an exclusive lock on a file, then do something with it.

public abstract class LockedFileOperation {

    public void execute(File file) throws IOException {

        if (!file.exists()) {
            throw new FileNotFoundException(file.getAbsolutePath());
        }

        FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
        // Get an exclusive lock on the whole file
        FileLock lock = channel.lock();
        try {
            lock = channel.lock();
            doWithLockedFile(file);
        } finally {
            lock.release();
        }
    }

    public abstract void doWithLockedFile(File file) throws IOException;
}

Here's a unit test I wrote, which creates a subclass of LockedFileOperation that attempts to rename the locked file

public void testFileLocking() throws Exception {

    File file = new File("C:/Temp/foo/bar.txt");
    final File newFile = new File("C:/Temp/foo/bar2.txt");

    new LockedFileOperation() {

        @Override
        public void doWithLockedFile(File file) throws IOException {
            if (!file.renameTo(newFile)) {
                throw new IOException("Failed to rename " + file + " to " + newFile);
            }
        }
    }.execute(file);
}

When I run this test, an OverlappingFileLockException is thrown when channel.lock() is called. It's unclear to me why this is happening, because I only ever try to lock this file once.

In any event, the JavaDocs for the lock() method say that:

An invocation of this method will block until the region can be locked, this channel is closed, or the invoking thread is interrupted, whichever comes first.

So even if the file was already locked it seems that the lock() method should block, rather than throwing an OverlappingFileLockException.

I guess there's something fundamental about FileLock that I'm misunderstanding. I'm running on Windows XP (in case that's relevant).

Thanks, Don

+3  A: 

You are locking twice the file and never release the first lock:

    // Get an exclusive lock on the whole file
    FileLock lock = channel.lock();
    try {
        lock = channel.lock();
        doWithLockedFile(file);
    } finally {
        lock.release();
    }

As you reuse the var lock, where do you release the first?

You code should be:

    // Get an exclusive lock on the whole file
    FileLock lock = null;
    try {
        lock = channel.lock();
        doWithLockedFile(file);
    } finally {
        if(lock!=null) {
           lock.release();
         }
    }
Tomas Narros
wow, that's embarassing, thanks!
Don