如何锁定文件

2023-12-26

我有一个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 http://docs.oracle.com/javase/1.5.0/docs/api/java/nio/channels/FileChannel.html#lock%28long,%20long,%20boolean%29其中提到:

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

那我做错了吗?如果是这样,正确的方法是什么?如果我做得对,为什么会陷入僵局?

Added:忘记提及 - 每个线程都拥有自己的该对象的副本,因此代码中不应存在任何同步问题。我感到可以安全地依赖FileChannel.lock()确保写入不会交错的方法。

还添加了:我确实已经使用各种方法解决了这个问题synchronized机制。然而,我确实有一些悬而未决的问题:

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

FileLock仅用于进程间锁定,javadoc http://docs.oracle.com/javase/1.4.2/docs/api/java/nio/channels/FileLock.html内容如下:

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

要在 Java 线程(同一 JVM)之间锁定,您需要使用一些共享锁。我建议在文件写入类中使用同步块(其中根据 http://my.safaribooksonline.com/book/programming/java/0321349601/explicit-locks/ch13lev1sec4 to these https://blogs.oracle.com/dave/entry/java_util_concurrent_reentrantlock_vs articles http://codeidol.com/java/java-concurrency/Explicit-Locks/Choosing-Between-Synchronized-and-ReentrantLock/可能表现最好):

final Object lock = new Object();

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

另一种方法是使用可重入锁 http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html然后使用经过验证的惯用法

final ReentrantLock lock = new ReentrantLock();

public void write(...){
  try {
    lock.lock()
    // do the writing
  } finally {
    // forget this and you're screwed
    lock.unlock();
  }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何锁定文件 的相关文章

随机推荐