OldCurmudgeon
OldCurmudgeon

Reputation: 65793

How to lock a file

I have a write method that is supposed to safely write data to a file.

// The current file I am writing to.
FileOutputStream file = null;
...
// Synchronized version.
private void write(byte[] bytes) {
  if (file != null && file.getChannel() != null) {
    try {
      boolean written = false;
      do {
        try {
          // Lock it!
          FileLock lock = file.getChannel().lock();
          try {
            // Write the bytes.
            file.write(bytes);
            written = true;
          } finally {
            // Release the lock.
            lock.release();
          }

        } catch (OverlappingFileLockException ofle) {
          try {
            // Wait a bit
            Thread.sleep(0);
          } catch (InterruptedException ex) {
            throw new InterruptedIOException("Interrupted waiting for a file lock.");
          }
        }
      } while (!written);
    } catch (IOException ex) {
      log.warn("Failed to lock " + fileName, ex);
    }
  } else {
    log.warn("Failing - " + (file == null ? "file" : "channel") + " is null!!");
  }
}

It has worked fine for me for a while now, although I know there are some wrinkles in it.

I have recently changed a project that uses this code to build and run under Java 5 (from Java 6) and now it looks like it is deadlocked awaiting a lock on the file. It is a multithreaded app and it is quite possible for several threads to attempt to write to the same file.

The debugger tells me that the hung threads are waiting for the FileLock lock = file.getChannel().lock() call to return.

Some research brought up this interesting little nugget which mentions:

File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine.

So am I doing it wrong? If so what is the right way? If I am doing it right how come I hit a deadlock?

Added: Forgot to mention - each thread holds its own copy of this object so there should not be any synchronisation issues within the code. I felt safe to rely on the FileChannel.lock() method to ensure writes do not interleave.

Added too: I have indeed solved the issue using various synchronized mechanisms. I do, however, have outstanding questions:

  1. Why is FileLock lock = file.getChannel().lock(); not suitable ...?
  2. Why did my issues only appear when switching back to Java-5 when everything worked fine with Java-6?

Upvotes: 4

Views: 7974

Answers (2)

cyber-monk
cyber-monk

Reputation: 5560

FileLock is only for interprocess locking, javadoc reads:

"File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine."

To lock between java threads (same JVM) you need to use some shared lock. I would suggest within the file writing class to use a synchronized block (which according to these articles is likely to perform best):

final Object lock = new Object();

public void write(...){
  synchronized(lock){
    // do writing
  }
}

Another approach is to use a ReentrantLock and then use the proven idiom of

final ReentrantLock lock = new ReentrantLock();

public void write(...){
  try {
    lock.lock()
    // do the writing
  } finally {
    // forget this and you're screwed
    lock.unlock();
  }
}

Upvotes: 4

srini.venigalla
srini.venigalla

Reputation: 5145

you may need to implement critical section concept on the actual code using the file, rather than the hashmap. You can either create a synchronized block or separate the file access code into a separate procedure and make that method synchronized.

Essentially, only one thread executes a synchronized block at a time. It gives you the exclusive access you need.

Another way of doing it is, to use a serial thread Executor, depending on your functional requirements.

You may want to look at this thread: Howto synchronize file access in a shared folder using Java (OR: ReadWriteLock on network level)

Upvotes: 1

Related Questions