共享锁允许多线程并发读,不互斥;排他锁独占资源,与所有锁互斥。二者核心区别在于兼容性:共享锁之间兼容,但与排他锁互斥;排他锁与任何锁均不兼容,确保写操作独占性。
共享锁与排他锁的本质区别共享锁(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 文件并确保每个实例有独立存储路径
