【问题标题】:Lock a file in Java with FileLock使用 FileLock 在 Java 中锁定文件
【发布时间】:2015-05-19 21:03:09
【问题描述】:

我正在尝试使用Java FileLock 写入文件,以禁止所有其他进程和线程读取或写入文件,直到我完成。鉴于this question 及其答案,在我看来,这是我想要的完美工具——用于文件访问的互斥锁。

不过,我很关心来自JavaDocs的这段文字:

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

有人可以减轻我的恐惧或为我指明正确的方向吗?听起来FileLock 根本无法将不同的线程保留在文件之外,即使另一个线程已经获得它。如果是这种情况,是否还有另一种规范的 Java 方法可以保护其他线程?

【问题讨论】:

  • 使用正常的互斥方法(synchronized 块或ReentrantLocks)来防止线程同时访问相同的资源。

标签: java multithreading locking


【解决方案1】:

FileLock 是进程级别的锁,因此不会保护文件免受来自拥有锁的进程中的多个线程的并发访问。

您需要在您的进程中使用FileLock 的组合来防止来自其他进程的并发访问和一些其他同步机制(例如用于访问文件的synchronized 方法)以防止您自己的并发访问线程。

【讨论】:

    【解决方案2】:

    我会这样实现:

    interface FileOperator {
      public void operate(File file);
    }
    
    class FileProxy {
      private static final ConcurrentHashMap<URI, FileProxy> map =
        new ConcurrentHashMap<>();
    
      private final Semaphore mutex = new Semaphore(1, true);
    
      private final File file;
    
      private final URI key;
    
      private FileProxy(File file) {
        this.file = file;
        this.key = file.toURI();
      }
    
      public static void operate(URI uri, FileOperator operator) {
        FileProxy curProxy = map.get(uri);
        if(curProxy == null) {
          FileProxy newProxy = new FileProxy(new File(uri));
          FileProxy curProxy = map.putIfAbsent(newProxy.key, newProxy);
          if(curProxy == null) {
            curProxy = newProxy; // FileProxy was not in the map
          }
        }
    
        try {
          curProxy.mutex.acquire();
          operator.operate(curProxy.file);
        } finally {
          curProxy.mutex.release();
        }
      }
    }
    

    使用文件的线程实现FileOperator 或类似的东西。文件隐藏在FileProxy 后面,该FileProxy 维护着一个静态的ConcurrentHashMap 键(URI,或绝对路径,或一些其他文件不变量)值(FileProxy)对。每个FileProxy 都维护一个Semaphore,它充当互斥锁——这是用一个许可初始化的。当调用静态operate 方法时,如果不存在则从URI 创建一个新的FileProxy;然后将FileOperator 添加到FileProxy 队列中;在互斥体上调用acquire,保证一次只能有一个线程对文件进行操作;最后FileOperator 完成了它的工作。

    在这个实现中,FileProxy 对象永远不会从 ConcurrentHashMap 中删除 - 如果这是一个问题,那么解决方案是将 FileProxy 对象包装在 WeakReferenceSoftReference 中,以便它们可以垃圾回收,然后在reference.get() == null 时调用map.replace 以确保只有一个线程替换GC'd 引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-20
      • 1970-01-01
      • 1970-01-01
      • 2015-10-18
      • 2014-12-10
      • 1970-01-01
      相关资源
      最近更新 更多