如何锁定文件

时间:2012-07-18 14:40:03

标签: java multithreading file file-io locking

我有一个write方法,可以安全地将数据写入文件。

// 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!!");
  }
}

现在它对我来说已经好了一段时间,虽然我知道它有一些皱纹。

我最近更改了一个使用此代码在Java 5(来自Java 6)下构建和运行的项目,现在看起来它已死锁,等待锁定文件。它是一个多线程应用程序,很多线程很可能尝试写入同一个文件。

调试器告诉我挂起的线程正在等待FileLock lock = file.getChannel().lock()调用返回。

一些研究提出了这个有趣的小nugget,其中提到:

  

代表整个Java虚拟机保存文件锁。 它们不适合控制同一虚拟机中多个线程对文件的访问。

我做错了吗?如果是这样,什么是正确的方法?如果我做得对,我怎么会遇到僵局?

已添加:忘记提及 - 每个帖子都拥有自己的此对象副本,因此代码中不应存在任何同步问题。依靠FileChannel.lock()方法确保写入不会交错,我感到安全。

已添加:我确实使用各种synchronized机制解决了这个问题。但是,我的问题很突出:

  1. 为什么FileLock lock = file.getChannel().lock(); 不合适?
  2. 为什么我的问题仅在切换回Java-5时出现,当Java-6的一切正常时?

2 个答案:

答案 0 :(得分:3)

FileLock仅用于进程间锁定,javadoc读取:

  

“文件锁代表整个Java虚拟机。   它们不适合控制多个文件的访问   同一虚拟机中的线程。“

要锁定java线程(相同的JVM),您需要使用一些共享锁。我建议在文件编写类中使用同步块(accordingthese articles可能表现最佳):

final Object lock = new Object();

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

另一种方法是使用ReentrantLock,然后使用

的成熟惯用法
final ReentrantLock lock = new ReentrantLock();

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

答案 1 :(得分:1)

您可能需要使用文件而不是hashmap在实际代码上实现关键部分概念。您可以创建同步块或将文件访问代码分离到单独的过程中,并使该方法同步。

基本上,一次只有一个线程执行同步块。它为您提供所需的独家访问权限。

另一种方法是使用串行线程Executor,具体取决于您的功能要求。

你可能想看一下这个帖子: Howto synchronize file access in a shared folder using Java (OR: ReadWriteLock on network level)