How to lock a file

旧时模样 提交于 2020-01-02 06:07:58

问题


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?

回答1:


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();
  }
}



回答2:


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)



来源:https://stackoverflow.com/questions/11543967/how-to-lock-a-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!