15.9.5 文件锁

15.9.5 文件锁

文件锁在操作系统中是很平常的事情,如果多个运行的程序需要并发修改同一个文件时,程序之间需要某种机制来进行通信,使用文件锁可以有效地阻止多个进程并发修改同一个文件,所以现在的大部分操作系统都提供了文件锁的功能。
文件锁控制文件的全部或部分字节的访问,但文件锁在不同的操作系统中差别较大,所以早期的JDK版本并未提供文件锁的支持。JDK1.4NIO开始,Java开始提供文件锁的支持

FileLock

NIO中,Java提供了FileLock来支持文件锁定功能。

如何获取FileLock

无参的lock和tryLock方法

FileChannel中提供的lock()tryLock()两个方法可以获得文件锁FileLock对象,从而锁定文件。

FileChannel获取FileLock的方法 描述
FileLock lock() 获取FileChannel对应的排它锁
FileLock tryLock() 获取FileChannel对应的排它锁

lock方法和tryLock方法的区别

lock()tryLock()方法存在区别:

  • lock()试图锁定某个文件时,如果无法得到文件锁,程序将一直阻塞;
  • tryLock()是尝试锁定文件,它将直接返回而不是阻塞,如果获得了文件锁,该方法则返回该文件锁,否则将返回null

部分锁定

如果FileChannel只想锁定文件的部分内容,而不是锁定全部内容,则可以使用如下的lock()tryLock()方法。

方法 描述
abstract FileLock lock(long position, long size, boolean shared) Acquires a lock on the given region of this channel’s file.
abstract FileLock tryLock(long position, long size, boolean shared) Attempts to acquire a lock on the given region of this channel’s file.

共享锁

带参数的locktryLock方法的参数sharedtrue时,表明该锁是一个共享锁,它将**允许多个进程来读取该文件,但阻止其他进程获得对该文件的排他锁**。(共享锁:别人可读不可写)

排他锁

带参数的locktryLock方法的参数sharedfalse时,表明该锁是一个排他锁,它将锁住对该文件的读写。(排它锁:别人不可读,也不可写)

直接使用lock()tryLock()方法获取的文件锁是排他锁

判断是否是共享锁

程序可以通过调用FileLockisShared()方法来判断它获得的锁是否为共享锁。

FileLockisShared方法 描述
boolean isShared() Tells whether this lock is shared.

释放文件锁

处理完文件后通过FileLockrelease()方法释放文件锁。

FileLockrelease方法 描述
abstract void release() Releases this lock.

程序 使用FileLock

下面程序示范了使用FileLock锁定文件的示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.io.*;
import java.nio.channels.*;

public class FileLockTest {
public static void main(String[] args) throws Exception {

try (
// 使用FileOutputStream获取FileChannel
FileChannel channel = new FileOutputStream("a.txt").getChannel()) {
// 使用非阻塞式方式对指定文件加锁
FileLock lock = channel.tryLock();
// 程序暂停10s
Thread.sleep(10000);
// 释放锁
lock.release();
}
}
}

上面程序中的代码:

1
FileLock lock = channel.tryLock();

用于对指定文件加锁,接着程序调用Thread.sleep(10000)暂停了10秒后才释放文件锁,因此在这10秒之内,其他程序无法对a.txt文件进行修改
文件锁虽然可以用于控制并发访问,但对于高并发访问的情形,还是推荐使用数据库来保存程序信息,而不是使用文件

文件锁需要注点的地方

关于文件锁还需要指出如下几点。

  • 在某些平台上,文件锁仅仅是建议性的,并不是强制性的。这意味着即使一个程序不能获得文件锁,它也可以对该文件进行读写
  • 在某些平台上,不能同步地锁定一个文件并把它映射到内存中
  • 文件锁是由Java虚拟机所持有的,如果两个Java程序使用同一个Java虚拟机运行,则它们不能对同一个文件进行加锁。
  • 在某些平台上关闭FileChannel时,会释放Java虚拟机在该文件上的所有锁,因此应该避免对同一个被锁定的文件打开多个FileChannel