如何在不同的应用程序级别锁定文件?
以下是场景:我有一个在 servlet 容器内运行的多线程 Java Web 应用程序.该应用程序在 servlet 容器内多次部署.有多个 servlet 容器在不同的服务器上运行.
Here's the scenario: I have a multi threaded java web application which is running inside a servlet container. The application is deployed multiple times inside the servlet container. There are multiple servlet containers running on different servers.
也许这张图说明了:
server1
+- servlet container
+- application1
| +- thread1
| +- thread2
+- application2
+- thread1
+- thread2
server2
+- servlet container
+- application1
| +- thread1
| +- thread2
+- application2
+- thread1
+- thread2
网络共享目录中有一个文件,所有这些线程都可以访问.他们确实经常访问该文件.大多数情况下,文件仅由这些线程读取.但有时是写出来的.
There is a file inside a network shared directory which all those threads can access. And they do access the file frequently. Most of the time the file is only read by those threads. But sometimes it is written.
无法正常工作的解决方案:
使用 java.nio.channels.FileLock
我能够使用 FileLock 类同步来自不同服务器的线程.但这不适用于线程在同一个进程(servlet 容器)内,因为文件锁在进程范围内可用.
Using java.nio.channels.FileLock
I am able to synchronize threads from different servers using the FileLock class. But this does not work for threads inside the same process (servlet container) since file locks are available process wide.
使用单独的文件进行同步
我可以创建一个单独的文件,表明一个进程正在读取或写入文件.这个解决方案适用于所有线程,但有几个缺点:
Using a separate file for synchronization
I could create a separate file which indicates that a process is reading from or wrinting to the file. This solution
works for all threads but has several drawbacks:
- 性能.创建、删除和检查文件是相当慢的操作.使用一个同步文件的低权重实现将阻止文件的并行读取.
- 在需要手动清理的 JVM 崩溃后,同步文件将保留.
- 我们在删除网络文件系统上的文件时遇到了奇怪的问题.
使用消息传递
我们可以实现一个消息系统,线程将使用它来协调文件访问.但这对于这个问题来说似乎太复杂了.再说一遍:性能会很差.
Using messaging
We could implement a messaging system which the threads would use to coordinate the file access. But this seems too complex for this problem. And again: performance will be poor.
有什么想法吗?
推荐答案
如果你只需要很少写文件,那么写一个临时名称的文件,然后使用重命名使其对读者可见"如何?
If you only need to write the file rarely, how about writing the file under a temporary name and then using rename to make it "visible" to the readers?
不过,这只适用于 Unix 文件系统.在 Windows 上,您需要处理某些进程打开文件(用于读取)的情况.在这种情况下,重命名将失败.重命名成功后再试.
This only works reliably with Unix file systems, though. On Windows, you will need to handle the case that some process has the file open (for reading). In this case, the rename will fail. Just try again until the rename succeeds.
我建议彻底测试一下,因为你可能会遇到拥塞:读取请求太多,写入任务很长时间无法替换文件.
I suggest to test this thoroughly because you might run into congestion: There are so many read requests that the writer task can't replace the file for a long time.
如果是这种情况,请让读取器检查临时文件并等待下一次读取,直到文件消失.
If that is the case, make the readers check for the temporary file and wait a few moments with the next read until the file vanishes.
相关文章