java中filechannel.lock()提供操作系统级建议性排他锁,需通过"rw"模式的randomaccessfile获取通道,可锁定文件区域(shared=false),跨jvm有效但不阻止未加锁程序访问,须显式release()释放。

Java 中使用 FileChannel 的 lock() 方法可以实现文件级别的排他锁(独占锁),确保同一时间只有一个进程(或 JVM 实例)能对文件进行写操作。注意:该锁是**操作系统级的 advisory lock**(建议性锁),依赖底层 OS 支持,且对其他不调用 lock 的程序无效;但同一 JVM 内多个线程/通道间能正确互斥。
获取可写的 FileChannel 并加锁
必须通过 RandomAccessFile 或 FileOutputStream/FileInputStream 的 getChannel() 获取通道,并确保通道处于可读写模式(rw)。只读通道无法加写锁。
- 用
RandomAccessFile("path", "rw")创建文件句柄 - 调用
getChannel()得到FileChannel - 调用
channel.lock()—— 阻塞直到获得锁(或抛OverlappingFileLockException)
lock() 方法的关键参数与行为
lock(long position, long size, boolean shared) 可指定锁定文件的某一段区域。排他锁需设 shared = false(默认 lock() 无参重载即为 shared=false)。
-
position=0, size=Long.MAX_VALUE:锁整个文件(最常用) - 若已存在重叠锁(如另一进程已锁),会抛
IOException(如OverlappingFileLockException) - 锁在
FileChannel关闭或 JVM 退出时自动释放,但应显式release()
安全加锁与异常处理示例
务必在 try-with-resources 或 finally 中释放锁,避免死锁或资源泄漏:
try (RandomAccessFile raf = new RandomAccessFile("data.txt", "rw");
FileChannel channel = raf.getChannel()) {
FileLock lock = channel.lock(); // 阻塞获取排他锁
try {
// 安全执行读写操作,例如:
channel.write(ByteBuffer.wrap("hello".getBytes()));
channel.force(true); // 确保数据刷盘
} finally {
lock.release(); // 显式释放锁(推荐)
}
} catch (IOException e) {
// 处理锁失败(如被占用)、IO 异常等
}
跨 JVM 进程锁的有效性说明
该锁在 Linux/macOS/Windows 上均有效,但有重要限制:
- 仅对调用
lock()的进程生效;不检查锁的程序仍可读写文件 - 不同 JVM 实例之间能互斥(因基于 OS 文件描述符)
- 同一 JVM 内多个
FileChannel对同一文件加锁会抛OverlappingFileLockException - 锁不随 fork 继承,子进程需重新获取
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











