![Java核心技术·卷Ⅱ:高级特性(原书第10版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/937/34339937/b_34339937.jpg)
2.6.3 文件加锁机制
考虑一下多个同时执行的程序需要修改同一个文件的情形,很明显,这些程序需要以某种方式进行通信,不然这个文件很容易被损坏。文件锁可以解决这个问题,它可以控制对文件或文件中某个范围的字节的访问。
假设你的应用程序将用户的偏好存储在一个配置文件中,当用户调用这个应用的两个实例时,这两个实例就有可能会同时希望写这个配置文件。在这种情况下,第一个实例应该锁定这个文件,当第二个实例发现这个文件被锁定时,它必须决策是等待直至这个文件解锁,还是直接跳过这个写操作过程。
要锁定一个文件,可以调用FileChannel类的lock或tryLock方法:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/105-i.jpg?sign=1739511431-toHBjNlxFMswr2iVRS2vn1niob2jMauc-0-347ca5e64206d6856c00f8ffe1aa67d2)
或
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/105-2-i.jpg?sign=1739511431-g59JssrG5aRE58e0yc3nqssU28TXXtB5-0-23efb42a6bfa2f55113350baef206025)
第一个调用会阻塞直至可获得锁,而第二个调用将立即返回,要么返回锁,要么在锁不可获得的情况下返回null。这个文件将保持锁定状态,直至这个通道关闭,或者在锁上调用了release方法。
你还可以通过下面的调用锁定文件的一部分:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/105-3-i.jpg?sign=1739511431-locWAP2egzMWCbSU6KWtkTZPMWGf0RN3-0-f05f06a15be681cda5d091d1c3df139b)
或
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/105-4-i.jpg?sign=1739511431-WlggF9JMql2SwDwf5ln77rdbvcBg1MFZ-0-5f575d9df716d00eda858138c8314a6e)
如果shared标志为false,则锁定文件的目的是读写,而如果为true,则这是一个共享锁,它允许多个进程从文件中读入,并阻止任何进程获得独占的锁。并非所有的操作系统都支持共享锁,因此你可能会在请求共享锁的时候得到的是独占的锁。调用FileLock类的isShared方法可以查询你所持有的锁的类型。
注意:如果你锁定了文件的尾部,而这个文件的长度随后增长超过了锁定的部分,那么增长出来的额外区域是未锁定的,要想锁定所有的字节,可以使用Long.MAX_VALUE来表示尺寸。
要确保在操作完成时释放锁,与往常一样,最好在一个try语句中执行释放锁的操作:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/105-5-i.jpg?sign=1739511431-aiTU3b0ziAtZ9qBR2RCaGlPKZF8PuJW3-0-9958aa6aeb0b86c137f0bd222acd2021)
请记住,文件加锁机制是依赖于操作系统的,下面是需要注意的几点:
·在某些系统中,文件加锁仅仅是建议性的,如果一个应用未能得到锁,它仍旧可以向被另一个应用并发锁定的文件执行写操作。
·在某些系统中,不能在锁定一个文件的同时将其映射到内存中。
·文件锁是由整个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
释放这个锁。