2.6.3 文件加锁机制
考虑一下多个同时执行的程序需要修改同一个文件的情形,很明显,这些程序需要以某种方式进行通信,不然这个文件很容易被损坏。文件锁可以解决这个问题,它可以控制对文件或文件中某个范围的字节的访问。
假设你的应用程序将用户的偏好存储在一个配置文件中,当用户调用这个应用的两个实例时,这两个实例就有可能会同时希望写这个配置文件。在这种情况下,第一个实例应该锁定这个文件,当第二个实例发现这个文件被锁定时,它必须决策是等待直至这个文件解锁,还是直接跳过这个写操作过程。
要锁定一个文件,可以调用FileChannel类的lock或tryLock方法:
或
第一个调用会阻塞直至可获得锁,而第二个调用将立即返回,要么返回锁,要么在锁不可获得的情况下返回null。这个文件将保持锁定状态,直至这个通道关闭,或者在锁上调用了release方法。
你还可以通过下面的调用锁定文件的一部分:
如果shared标志为false,则锁定文件的目的是读写,而如果为true,则这是一个共享锁,它允许多个进程从文件中读入,并阻止任何进程获得独占的锁。并非所有的操作系统都支持共享锁,因此你可能会在请求共享锁的时候得到的是独占的锁。调用FileLock类的isShared方法可以查询你所持有的锁的类型。
注意:如果你锁定了文件的尾部,而这个文件的长度随后增长超过了锁定的部分,那么增长出来的额外区域是未锁定的,要想锁定所有的字节,可以使用Long.MAX_VALUE来表示尺寸。
要确保在操作完成时释放锁,与往常一样,最好在一个try语句中执行释放锁的操作:
请记住,文件加锁机制是依赖于操作系统的,下面是需要注意的几点:
- 在某些系统中,文件加锁仅仅是建议性的,如果一个应用未能得到锁,它仍旧可以向被另一个应用并发锁定的文件执行写操作。
- 在某些系统中,不能在锁定一个文件的同时将其映射到内存中。
文件锁是由整个Java虚拟机持有的。如果有两个程序是由同一个虚拟机启动的(例如Applet和应用程序启动器),那么它们不可能每一个都获得一个在同一个文件上的锁。当调用lock和tryLock方法时,如果虚拟机已经在同一个文件上持有了另一个重叠的锁,那么这两个方法将抛出OverlappingFileLockException。 - 在一些系统中,关闭一个通道会释放由Java虚拟机持有的底层文件上的所有锁。因此,在同一个锁定文件上应避免使用多个通道。
- 在网络文件系统上锁定文件是高度依赖于系统的,因此应该尽量避免。
java.nio.channels.FileChannel 1.4
- FileLock lock()
在整个文件上获得一个独占的锁,这个方法将阻塞直至获得锁。 - FileLock tryLock()
在整个文件上获得一个独占的锁,或者在无法获得锁的情况下返回null。 - FileLock lock(long position, long size, boolean shared)
- FileLock tryLock(long position, long size, boolean shared)
在文件的一个区域上获得锁。第一个方法将阻塞直至获得锁,而第二个方法将在无法获得锁时返回null。
参数:position 要锁定区域的起始位置
size 要锁定区域的尺寸
shared true为共享锁,false为独占锁
java.nio.channels.FileLock 1.4
- void close() 1.7
释放这个锁。