java本地锁无法跨jvm使用,分布式锁需满足互斥性、防死锁、解铃还须系铃人、原子性四条件;推荐用redis的set命令(nx+px+唯一value)加锁,lua脚本校验value后删锁;生产环境优先选用redisson,支持自动续期、可重入及redlock。

Java 中的本地锁(比如 synchronized 或 ReentrantLock)只在单 JVM 进程内有效,无法跨机器、跨服务起作用。要实现分布式环境下的排他访问,必须借助外部共享存储——Redis 是最常用、性能最优的选择之一。
核心目标:满足分布式锁的四个刚性条件
不是“能用就行”,而是必须同时保障:
- 互斥性:同一时刻,仅一个客户端持有锁;
- 防死锁:持有锁的进程崩溃后,锁能自动释放(靠过期时间);
- 解铃还须系铃人:只有加锁者才能删锁,避免误删他人锁(靠唯一 request ID);
- 原子性:加锁动作本身不可拆分,否则可能 setnx 成功但 expire 失败,导致无过期的“幽灵锁”。
推荐做法:用 SET 命令一步完成加锁
直接使用 Jedis 或 RedisTemplate 的 set(key, value, "NX", "PX", expireMs) 方法:
-
NX表示“仅当 key 不存在时才设置”,天然实现互斥; -
PX指定毫秒级过期时间,避免死锁; -
value必须是全局唯一标识(如 UUID),后续解锁时用于校验身份; - 整个命令在 Redis 内部原子执行,彻底规避“setnx + expire”两步非原子的风险。
安全解锁:必须用 Lua 脚本校验再删除
不能简单调 DEL key,否则 A 进程锁已过期被 B 获取,A 结束后仍 DEL,就误删了 B 的锁。正确方式是:
- 写一段 Lua 脚本:先 GET key,比对 value 是否等于自己的 request ID,相等才 DEL;
- 通过
eval原子执行该脚本; - 返回 1 表示解锁成功,0 表示锁已被他人持有或已过期。
进阶建议:优先用 Redisson 而非手写
自己实现容易遗漏重入、看门狗续期、集群 failover 等细节。Redisson 封装了成熟方案:
- 自动为锁续期(WatchDog 机制),防止业务执行慢导致锁提前释放;
- 支持可重入(同一线程多次 lock() 只加一次计数);
- 内置 RedLock 算法,提升多节点部署下的容错能力;
- 提供
RLock接口,用法接近ReentrantLock,学习成本低。
不复杂但容易忽略。关键不在“能不能加锁”,而在“加得稳、解得准、扛得住异常”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











