在我之前的问题中,我发现您可以使用 FileChannel 的锁来确保读取和写入的顺序。
但是,如果编写器在写入过程中失败(比如 JVM 崩溃),您将如何处理这种情况?这个基本算法看起来像,
WRITER:
lock file
write file
release file
READER:
lock file
read file
release file
如果 JVM 在 期间崩溃write file
,肯定会释放锁,但现在我有一个不完整的文件。我想要完整的东西总是可读的。要么是旧内容,要么是新内容,两者之间没有任何内容。
我的第一个策略是写入一个临时文件,然后将内容复制到“实时”文件中(同时确保良好的锁定)。算法是,
WRITER:
lock temp file
write temp file
lock file
copy temp to file
release file
release temp
delete temp
READER:
lock file
read file
release file
一件好事是,delete temp
如果临时文件已被另一位作家锁定,则不会删除临时文件。
但是如果 JVM 在copy temp to file
. 然后我添加了一个copying
标志,
WRITER:
lock temp file
write temp file
lock file
create copying flag
copy temp to file
delete copying flag
release file
release temp
delete temp
READER:
lock file
if copying flag exists
copy temp to file
delete copying flag
delete temp
end
read file
release file
永远不会有两件事访问该copying
文件,因为它受到文件锁的保护。
现在,这是这样做的方法吗?确保非常简单的事情似乎很复杂。是否有一些 Java 库可以为我处理这个问题?
编辑
好吧,我设法在第三次尝试中犯了一个错误。阅读器不会将锁锁定到 temp copy temp to file
。简单地锁定临时文件也不是一个简单的修复!这将导致写入者和读取者以不同的顺序获取锁,并可能导致死锁。这一直在变得越来越复杂。这是我的第四次尝试,
WRITER:
lock file
write temp file
create copying flag
copy temp to file
delete copying flag
delete temp
release file
READER:
lock file
if copying flag exists
copy temp to file
delete copying flag
delete temp
end
read file
release file
这次临时文件由主锁保护,因此它甚至不需要自己的锁。
编辑 2
当我说 JVM 崩溃时,我的意思是说电源坏了,而你没有 UPS。
编辑 3
我仍然设法犯了另一个错误。您不应该锁定您正在写入或读取的文件。这将导致问题,因为除非您在 Java 中使用 RandomAccessFile,否则您无法同时获得读取和写入锁,它不实现输入/输出流。
相反,您要做的只是锁定一个锁定文件,该锁定文件保护您正在读取或写入的文件。这是更新的算法:
WRITER:
lock
write temp file
create copying flag
copy temp to file
delete copying flag
delete temp
release
READER:
lock
if copying flag exists
copy temp to file
delete copying flag
delete temp
end
read file
release
锁定和释放保护文件、临时文件和复制标志。唯一的问题是现在不能共享读卡器锁,但它永远不可能真正共享。读者总是有机会修改文件,因此一开始就创建一个可共享的锁是错误的。