如何锁定文件

我有一个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)下构建和运行的项目,现在看起来它已死锁,等待锁定文件。 它是一个multithreading应用程序,很multithreading很可能尝试写入同一个文件。

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

一些研究提出了这个有趣的小金块 ,提到:

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

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

补充:忘记提及 – 每个线程都拥有自己的此对象副本,因此代码中不应存在任何同步问题。 依靠FileChannel.lock()方法来确保写入不会交错,我感觉很安全。

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

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

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

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

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

 final Object lock = new Object(); public void write(...){ synchronized(lock){ // do writing } } 

另一种方法是使用ReentrantLock ,然后使用经过validation的成语

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

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

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

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

您可能需要查看此线程: 如何使用Java同步文件访问共享文件夹(或者:网络级别的ReadWriteLock)