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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/320159/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 11:56:55  来源:igfitidea点击:

Howto synchronize file access in a shared folder using Java (OR: ReadWriteLock on network level)

javasynchronizationfile-access

提问by Eduard Wirch

I have multiple applications running in one virtual machine. I have multiple virtual machines running on one server. And I have multiple servers. They all share a file using a shared folder on linux. The file is read and written by all applications. During the write process no application is allowed to read this file. The same for writing: If an application is reading the file no application is allowed to write it.

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

How do I manage to synchronize the applications so they will wait for the write process to finish before they read, and vice versa? (the applications inside a vm have to be synchronized and also applications across servers)

我如何设法同步应用程序,以便它们在读取之前等待写入过程完成,反之亦然?(虚拟机内的应用程序必须同步,跨服务器的应用程序也必须同步)

Curent implementationuses "file semaphores". If the file is about to be written the application tries to "acquire" the semaphore by creating an additional file (lets name it "file.semaphore") in the shared folder. If the "file.semaphore" file already exists this means the semaphore is already locked by a different application. This approach has the problemthat I cannot make sure that the "file exists"-test and "create file"- operation are executed atomic. This way it is possible that two applications test for the "file.semaphore" file, see it does not exist and try to create the file at the same time.

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

回答by Ivan Dubrov

You can use NIO locking capabilities. See FileChannel#lock().

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

However, this will work only if underlying filesystem supports locking over the network. Recent NFS should support it. Probably, Samba supports them too, but can't say for sure.

但是,这仅在底层文件系统支持通过网络锁定时才有效。最近的 NFS 应该支持它。可能,Samba 也支持它们,但不能肯定。

See articlefor example.

例如见文章

回答by Andrzej Doyle

Have a look at the Javadocs for the createNewFile()method - it specifically states that creating files is not a reliable method for synchronization, and recommends the FileLockclass instead (it's another package in java.nio.channels so is essentially the same as what Ivan Dubrov is suggesting).

查看createNewFile()方法的 Javadocs - 它特别指出创建文件不是一种可靠的同步方法,并推荐使用FileLock类(它是 java.nio.channels 中的另一个包,因此本质上与伊万·杜布罗夫建议)。

This would imply that your identification of the problem is accurate, and no amount of playing around will solve this with traditional file creation. My first thought was to check the return code from createNewFile(), but if the Javadocs say it's not suitable then it's time to move on.

这意味着您对问题的识别是准确的,并且通过传统的文件创建无法解决此问题。我的第一个想法是检查 createNewFile() 的返回代码,但如果 Javadoc 说它不合适,那么是时候继续了。

回答by David I.

Need to combine file locking for protection between JVM's with synchronization within threads of a given JVM. See the answer by cyber-monk here

需要结合文件锁定来保护 JVM 与给定 JVM 的线程内的同步。在此处查看网络僧侣的答案

回答by Chris

I am also trying to determine the best way to solve this problem for a similar situation (less participating processes, but still same underlying problem). If you haven't been able to employ the file locking scheme suggested by Ivan (e.g. system|language|network service does not support it), maybe you could designate one of the participants as a referee. All participants write unique semaphores, call them "participant#.request" when they want the file. The referee polls the file system for these semaphores. When he sees one, he writes back "participant#.lock", and deletes the request. If he happens to see multiple at the "same time" he selects one at random (or first by file modification time) and deletes only their request. Then, the participant issued the lock knows they can access the file safely. When the participant is done with the file, they delete their own lock. While there is a lock in place, no other locks are issued by the referee. Any requests that are present after the user deletes their lock could be served a new lock without issuing a new request, so you could have the other users poll for their lock after sending the request. Probably this is what the locking mechanism is doing anyway, except maybe for the ability to manage the lock as a queue that comes with requests being processed in the order they are received (i.e. if the referee uses modification time). Also, since you're in charge of the referee you could set timeouts to locks, allowing him issue timeout semaphores to the process that is hogging the file and then remove the lock (hoping of course that if that process with the lock died, it did so nicely).

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