Java下Windows环境下的并发文件写入

17

当您同时打开两个(或多个)FileOutputStreams 的相同文件会发生什么?

Java API 表示如下:

有些平台特别是允许一个文件同时只被一个 FileOutputStream(或其他文件写入对象)打开进行写入。

我猜Windows不是这样的平台,因为我有两个线程读取一些大文件(每个线程读取不同的文件),然后将它们写入同一个输出文件。 没有抛出异常,文件已经创建,并且似乎包含来自两个输入文件的块。

附加问题:

  • Unix也是这样吗?
  • 既然我想要行为相同(实际上我想要一个线程正确地写入,另一个线程被警告存在冲突),那么如何确定文件已经被打开进行写入?
4个回答

17

当前没有一种可靠的、跨平台的被动通知方式,能够在文件有另一个写入者时发出异常信号,即如果文件已经打开进行写操作,则会抛出异常。然而,有几种技术可以帮助您主动检查这一点。

如果可能有多个进程(包括Java和非Java)使用该文件,则应使用FileLock。成功使用文件锁的关键是要记住它们只是“建议性的”。如果您检查锁定,就保证可以看到它,但如果您忘记了,它不会阻止您对文件进行操作。访问文件的所有进程都应设计为使用锁定协议。

如果单个Java进程正在处理该文件,则可以使用内置于Java中的并发工具来安全地进行操作。您需要一个对所有线程可见的映射,将每个文件名与其相应的锁实例相关联。可以很容易地将相关问题的答案适应为使用File对象或规范路径指向文件。锁对象可以是一个FileOutputStream,围绕该流的一些包装器,或者ReentrantReadWriteLock


4
我建议您小心让操作系统为您确定文件状态(因为这取决于操作系统)。如果您有共享资源,我建议使用可重入锁来限制对其的访问。
使用此锁意味着一个线程可以获取资源(文件)并写入它。下一个线程可以检查另一个线程是否持有此锁,并/或无限期地阻塞,直到第一个线程释放它。
Windows(我认为)会限制两个进程写入同一文件。我不认为Unix会这样做。

但是我不想在写入时阻塞,如果有人已经在写入文件,我想要阻塞。实际上,我根本不想阻塞。我想告诉第二个线程他不能写入,并让客户端决定后续操作。 - Andrei Vajna II
检查锁定的API。您可以检查锁定以确定是否有其他人已经锁定它(即未阻止),然后决定该怎么做。 - Brian Agnew

1
如果你所说的这2个线程在同一个JVM中,那么你可以在某个地方设置一个布尔变量,让这2个线程都可以访问。

0

Unix允许多个写入者同时写入同一个文件。

如果您尝试多次写入同一文件,则存在设计缺陷,应避免这种情况发生。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接