filelock的排他锁与共享锁本质是跨进程协调契约:排他锁禁止任何重叠区域加锁,确保写隔离;共享锁允许多读但阻塞写,且均不防未加锁操作。

FileLock 的排他锁与共享锁在多进程并发中表现截然不同,核心差异不在“能不能加锁”,而在于“谁和谁能共存”。它们不是线程安全工具,而是跨 JVM 进程协调的底层契约——生效前提是所有参与者都走同一套规则。
排他锁:写操作的硬隔离
调用 lock(0, Long.MAX_VALUE, false) 或默认 lock() 时获得。一旦某进程成功持有该锁(哪怕只锁了 1 字节),其他任何进程对重叠区域尝试加锁——无论排他还是共享——都会失败(抛 OverlappingFileLockException 或 tryLock() 返回 null)。它确保写入期间文件不会被其他进程读或写,但不阻止未加锁的外部操作(如 echo "x" > file)。
- Windows 下部分场景会拦截未加锁的写入,报错或阻塞
- Linux/macOS 默认放行,锁仅对主动调用
tryLock()的程序起作用 - 锁绑定的是“打开的文件描述符”,不是路径;两个进程分别
new FileOutputStream("a.txt"),各自拿到不同 fd,锁才真正互斥
共享锁:读操作的宽松协同
调用 tryLock(0, Long.MAX_VALUE, true) 获取。多个进程可同时持有共享锁,彼此不冲突;但它会阻止其他进程对重叠区域加排他锁。注意:某些系统(如 Windows)不支持共享锁,请求会被自动降级为排他锁,isShared() 返回 false 可验证实际类型。
从 AI 编程会话日志(Clawdbot、Claude Code、Codex)中提取对话记录。该功能用于在用户要求导出提示词历史、会话日志或 `.jsonl` 格式的会话文件时使用。
- 共享锁存在时,其他进程仍可加共享锁,但无法加任何排他锁
- 即使只加了 [0, 100) 的共享锁,另一进程尝试对 [99, 200) 加排他锁也会失败——因字节范围重叠
- 共享锁不能防止未加锁的写入,也不能保证读取时数据不被修改(除非所有写方也严格用排他锁)
锁失效的常见真实原因
看到“另一进程还在写”不等于锁没起作用,大概率是有人没守约:
- 一个进程用
FileOutputStream写文件但没调getChannel().lock(),锁形同虚设 - 容器环境挂载了 NFS/CIFS/overlay2 卷,底层文件系统不支持 POSIX flock
- K8s 多 Pod 共享同一 PV,旧进程崩溃后锁残留,新进程因检测到已有锁而拒绝启动
- 误用
FileInputStream.getChannel()——返回通道默认不可写,lock()可能返回 null 或抛异常
正确使用的关键动作
让锁真正协同,必须统一入口、显式释放、全程覆盖:
- 所有进程打开文件时,必须用
RandomAccessFile("f", "rw")或FileOutputStream+getChannel(),避免只读通道 - 写操作必须走 “
channel.tryLock() → 写入 → lock.release()” 流程,且放在finally块中 - 读操作若需强一致性,也应加共享锁;否则仅靠共享锁无法防止并发写入
- 不要依赖
isValid()判断是否“还被我占着”——它只反映锁是否被显式释放或通道关闭










