java nio文件锁需用filechannel.lock()实现跨进程同步:读用共享锁channel.lock(pos,size,true),写用独占锁channel.lock(pos,size,false);须按字节范围精确加锁、finally中释放,且所有访问方必须统一遵循nio加锁协议。

Java NIO 中的读写冲突,本质是多个线程或进程同时操作同一文件区域导致的数据不一致。解决它不能靠 synchronized 或 ReentrantLock 这类 JVM 级锁,因为它们只在单个进程内有效;必须用操作系统级的文件锁——即 FileChannel.lock() 机制。
明确锁类型:读用共享锁,写用独占锁
文件锁分两种,选错会导致读被阻塞或写不安全:
-
读操作(多线程并发读):调用
channel.lock(pos, size, true)获取共享锁,允许多个线程同时持有,但会阻止任何写锁介入 -
写操作(必须互斥):调用
channel.lock(pos, size, false)获取独占锁,默认行为,禁止其他读/写锁重叠 - 注意:
lock()不带参数时锁定整个文件且为独占锁;tryLock()是非阻塞版本,失败立即返回null
锁必须作用于具体字节范围,避免全局锁拖慢性能
不要一上来就锁整个文件,尤其对大文件或部分更新场景:
- 例如日志文件只追加末尾,可只锁最后 1KB 区域:
channel.lock(fileSize, 1024, false) - 数据库索引文件按块管理,可对每个逻辑块(如 offset=4096×n,size=4096)单独加锁
- 同一文件不同区域可并行加锁(如 [0,100) 和 [200,300)),只要不重叠就不会冲突
正确释放与异常防护是关键防线
锁不释放 = 死锁风险 + 其他进程永远等不到;异常未捕获 = 锁泄露:
- 必须在
finally块中调用fileLock.release(),不能依赖 GC 或 JVM 退出 - 遇到
OverlappingFileLockException,说明当前 JVM 内已有线程锁了重叠区域——需检查是否重复打开同一文件创建多个FileChannel,建议复用通道或加外部同步(如synchronized方法块) - 遇到
FileLockInterruptionException,说明等待锁的线程被中断,应捕获后清理资源并决定是否重试
跨进程才真正生效,纯 Java 锁无效
要记住这个根本前提:
-
FileLock是操作系统提供的 advisory lock(建议性锁),仅对同样调用lock()/tryLock()的进程起作用 - 用
FileOutputStream直接写、命令行echo >>、Python 的open(..., 'a')都不会被阻塞——它们不遵守该锁协议 - 所以必须确保所有访问方(包括脚本、其他语言程序、微服务实例)统一走 NIO 加锁路径,否则锁形同虚设
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











