共享锁允许多线程并发读,不互斥;排他锁独占资源,与所有锁互斥。二者核心区别在于兼容性:共享锁之间兼容,但与排他锁互斥;排他锁与任何锁均不兼容,确保写操作独占性。

共享锁与排他锁的本质区别
共享锁(shared=true)允许多个进程同时持有,适用于只读场景;它不阻止其他进程获取共享锁,但会阻止任何进程获取重叠区域的排他锁。排他锁(shared=false,默认)是独占的,一旦被一个进程持有,其他进程无论尝试共享锁还是排他锁,只要范围重叠,就无法成功。
关键点在于“重叠”:哪怕只是字节范围有 1 字节交集,操作系统就会拒绝加锁请求。例如进程 A 对 [0, 1024) 加了共享锁,进程 B 尝试对 [1023, 2048) 加排他锁,仍会被拒绝。
跨进程冲突的真实表现
FileLock 是 advisory lock(建议性锁),不是强制锁。它的生效完全依赖所有参与者主动调用 tryLock() 或 lock() 并检查返回值。绕过锁机制的操作(如 shell 中直接 echo "x" > file、Python 的 open().write()、或 Java 中未加锁的 FileOutputStream.write())不会被拦截。
- Windows 下行为较严格:未加锁的写操作常被阻塞或报错
- Linux 下更宽松:多数情况允许绕过,尤其使用 fopen/fwrite 或 cat 等工具时
- 因此,冲突不是“锁没起作用”,而是“有人根本没守约”
避免冲突的核心实践
要让锁在多进程间真正协同,必须统一入口和协议:
- 所有进程打开文件时必须指定 StandardOpenOption.READ 或 StandardOpenOption.WRITE,否则 tryLock() 可能静默失败或抛异常
- 写操作一律走 FileChannel.lock() → 写入 → release() 流程,读操作可选 tryLock(0, Long.MAX_VALUE, true)
- 不要混用流式 API(如 FileInputStream)和通道锁——它们的底层通道可能不可写,导致 lock() 返回 null
- 务必在 finally 块中调用 fileLock.release(),并捕获 IOException(比如锁已被另一进程释放)
常见误判与排查要点
看到 FileLock != null 不代表安全;看到 IOException: No locks available 也不代表系统锁资源耗尽。
- isValid() 只反映锁是否被显式释放或通道是否关闭,不能用于判断“当前是否仍被我占用”
- tryLock() 返回 null 是正常流程分支,不是异常,需按业务逻辑处理(如重试、跳过、报状态)
- 若多个 Pod 共享同一 PV 目录(如 Ignite 的 PDS),旧进程崩溃后锁残留,新进程会因检测到已有锁而失败——此时应清理 lock 文件 并确保每个实例有独立存储路径










