java的filelock是操作系统级建议性锁,必须所有进程主动配合才生效;它绑定文件描述符而非路径,仅通过可读写filechannel加锁才有效,绕过则失效。

Java NIO 的 FileLock 能在多进程场景下提供操作系统级的建议性锁(advisory lock),但**必须所有进程都主动配合才能生效**。它不阻塞绕过锁的文件操作,也不具备强制排他能力——关键在于规范使用方式和理解其边界。
必须用 FileChannel 获取锁,且通道需可读写
锁不是加在文件路径上,而是绑定到打开的文件描述符。只有通过 FileChannel 才能真正触发 OS 层锁机制:
- ✅ 正确:用
RandomAccessFile("file.txt", "rw").getChannel()或FileOutputStream(..., true).getChannel() - ❌ 错误:仅用
FileInputStream或FileOutputStream直接写入,不走getChannel().lock()—— OS 完全看不见锁 - ⚠️ 注意:
FileInputStream.getChannel()返回的 channel 默认不可写,调tryLock(0, 1, false)会抛NonWritableChannelException
按区域加锁,避免全文件互斥
用 tryLock(long position, long size, boolean shared) 划分逻辑区,提升并发度:
- 例如:前 64 字节存校验头 →
tryLock(0, 64, true)(共享读) - 第 64–72 字节存版本号 →
tryLock(64, 8, false)(独占写) - 从第 72 字节开始为主数据区 →
tryLock(72, Long.MAX_VALUE, false) - position + size 可超过当前文件长度,支持锁定“未来写入区域”,适合预分配日志块
正确释放锁,防止资源泄漏
锁对象生命周期独立于 Java 对象,必须显式释放:
- 务必在
finally块中调用fileLock.release() - 即使发生异常、线程中断或 JVM 异常退出,也要确保释放;否则锁可能残留数小时
- 不要依赖
FileLock.isValid()控制业务逻辑,它只反映锁是否被显式释放或通道关闭 - 关闭
FileChannel也会自动释放锁,但显式release()更清晰可控
注意运行环境限制,别在 NFS/容器里硬扛
FileLock 在部分文件系统上会降级或失效:
- Linux ext4 支持 POSIX fcntl 区域锁,行为符合预期
- NFSv3、CIFS、Docker overlay2 等不支持区域语义 →
tryLock(100, 512, false)实际等效于锁整个文件 - 可通过
df -T /path查看挂载类型;若显示nfs、cifs或overlay,应改用 Redis 分布式锁等外部协调机制 - Windows 上虽为 mandatory lock,但仅对同一句柄 I/O 生效,跨进程仍需所有参与者守约
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











