多个线程访问同一个文件

时间:2013-11-15 13:09:57

标签: java multithreading swing java-ee thread-safety

我有两个处理相同文件的函数:

public MyShelf(){
     …
  //Change the content of note.txt file
  public synchronized void updateFile(){
      File file = getFileUnderPath("PATH\note.txt");
      //Code to update the content of the file
      ...
  }
  //remove note.txt file
  public synchronized void removeFile() throws IOException {
      File file = getFileUnderPath("PATH\note.txt");
      file.delete();
      ...
  }
}

如上所述,有两个功能:

  • updateFile()函数更改了文件的内容

  • removeFile()功能删除文件。

这两个函数都处理名为 note.txt

的同一文件

由于可能有多个线程调用上述任一函数,这就是我使用synchronized关键字使我的程序线程安全的原因。

但是我不确定使用synchronized关键字后我的程序现在真的是线程安全吗?我是否还会遗漏某些东西或者是否有更好的方法让它保持线程安全?

7 个答案:

答案 0 :(得分:2)

Java nio package 旨在允许此操作。

您可以将一个文件的多个区域映射到不同的缓冲区,每个缓冲区可以由一个单独的线程单独填充。

答案 1 :(得分:1)

它是线程安全的,因为它是肯定的。在方法上同步基本上使用实例作为方法的整个块的锁:没有两个线程能够在同一个实例上调用synchronized方法。

但是,如果您有2个具有硬编码文件路径的MyShelf实例,则可能线程A可以在实例1上调用update,而线程B可以在实例2上调用remove。

答案 2 :(得分:1)

因为“线程中的每个动作happens-before该线程中的每个动作都在程序的顺序中出现,”一种方法是让updateFile()在完成时调用delete()更新文件。

或者,让updateFile()将完成的文件添加到BlockingQueue的合适实现中,其他等待线程可以安全地delete()

答案 3 :(得分:0)

可以尝试类似:

public MyShelf(){
     …
  Object theLock = new Object();
  //Change the content of note.txt file
  public void updateFile(){
      synchronized (theLock) {
         File file = getFileUnderPath("PATH\note.txt");
         //Code to update the content of the file
         ...
      }
  }
  //remove note.txt file
  public void removeFile() throws IOException {
    synchronized (theLock) {
      File file = getFileUnderPath("PATH\note.txt");
      file.delete();
      ...
    }
  }
}

答案 4 :(得分:0)

更好的同步方法是使用文件锁:How can I lock a file using java (if possible)

MyShelf的不同实例彼此不同步,因此如果同一文件有两个MyShelf实例,则可能同时更新此文件。

另一种选择是引入文件管理器并确保您的应用中不使用直接文件访问。但是,这不会让您免于同时运行两个应用实例的情况。

答案 5 :(得分:0)

synchronized是用于线程安全的强力方法,但工作正常并且您正确使用它。所以你的代码是线程安全的,因为2个线程不可能同时写入和删除文件。

然而,如果一个线程首先删除该文件,然后另一个线程尝试写入该文件,这显然是一个问题,但这是一个逻辑问题,需要重构您的代码。一个简单的例子是添加一个在write方法中检查的布尔变量isDeleted

我说暴力因为synchronized不是特别精细,它只是锁定整个代码块(在你的情况下是方法)并阻止访问多个线程,无论是什么实际上里面的函数是没有同步的线程安全的。因此,通过不必要的阻塞可以减少一些可能的执行速度。如果您想应用更细粒度的同步,则需要为您的代码开发更智能 - 因此更容易出错的 - 架构。

虽然使用并发软件包的各种工具绝对可以实现,但最大的问题是:您实际获得的速度有多快,是否值得付出额外的努力(包括调试)? 在你的情况下,性能的主要部分无论如何都会在文件操作中丢失,这本质上非常慢(与CPU操作相比)。因此,即使您要开发一种减少锁定的智能方法,性能的提升也可以忽略不计,而且很可能不值得花时间和精力。

简而言之:是的,你做得对,但需要考虑一些事情来防止写入已删除的文件。

答案 6 :(得分:-1)

不,这不安全。

synchronized表示只有一个线程将进入特定功能。 但是有可能一个线程正在排除updateFile()而另一个线程正在执行removeFile(),那么JVM将抛出异常。

因此,为了避免这种情况,请设置一个布尔变量,并在某个线程进入函数时切换它。