如何使用Java同步共享文件夹中的文件访问(或者:网络级别的ReadWriteLock)

我在一个虚拟机中运行多个应用程序。 我在一台服务器上运行多个虚拟机。 我有多台服务器。 它们都使用linux上的共享文件夹共享文件。 所有应用程序都会读取和写入该文件。 在写入过程中,不允许任何应用程序读取此文件。 写入相同:如果应用程序正在读取文件,则不允许应用程序写入它。

如何设置同步应用程序,以便它们在读取之前等待写入过程完成,反之亦然? (必须同步vm中的应用程序以及跨服务器的应用程序)

Curent实现使用“文件信号量”。 如果要写入文件,应用程序会尝试通过在共享文件夹中创建一个附加文件(将其命名为“file.semaphore”)来“获取”信号量。 如果“file.semaphore”文件已存在,则表示信号量已被其他应用程序锁定。 这种方法的问题是我无法确保“文件存在”-test和“create file” – 操作是primefaces执行的。 这样,两个应用程序可能会测试“file.semaphore”文件,看它不存在并尝试同时创建该文件。

您可以使用NIO锁定function。 请参阅FileChannel#lock() 。

但是,只有当底层文件系统支持锁定网络时,这才有效。 最近的NFS应该支持它。 也许,Samba也支持他们,但不能肯定地说。

例如,参见文章 。

看一下createNewFile()方法的Javadocs – 它明确指出创建文件不是一种可靠的同步方法,而是建议使用FileLock类(它是java.nio.channels中的另一个包,所以基本上与Ivan Dubrov建议)。

这意味着您对问题的识别是准确的,并且没有多少游戏可以解决传统文件创建问题。 我的第一个想法是检查来自createNewFile()的返回码,但如果Javadocs认为它不合适,那么就该继续前进了。

需要将文件锁定与JVM的保护结合在一起,以便在给定JVM的线程内实现同步。 在这里查看网络僧侣的答案

我也在尝试确定解决类似情况的最佳方法(参与进程较少,但仍存在相同的潜在问题)。 如果您未能使用Ivan建议的文件锁定方案(例如系统|语言|网络服务不支持它),也许您可​​以指定其中一个参与者作为裁判。 所有参与者都会写出独特的信号量,当他们想要文件时称他们为“参与者#.request”。 裁判轮询文件系统以获取这些信号量。 当他看到一个时,他回写“参与者#.lock”,并删除该请求。 如果他碰巧在“同一时间”看到多个,他随机选择一个(或者首先按文件修改时间)并且仅删除他们的请求。 然后,参与者发出锁知道他们可以安全地访问该文件。 当参与者完成文件后,他们会删除自己的锁。 虽然存在锁定,但裁判员不会发出其他锁定。 用户删除锁定后出现的任何请求都可以在不发出新请求的情况下为新锁提供服务,因此您可以让其他用户在发送请求后轮询其锁定。 这可能是锁定机制正在做的事情,除了可能将管理锁定为一个队列,其中请求按接收顺序处理(即,如果裁判使用修改时间)。 此外,由于您负责裁判,您可以将超时设置为锁定,允许他向占用文件的进程发出超时信号量,然后移除锁定(希望当然如果该进程锁定死亡,它做得很好)。