分布式锁与本地重入锁目标一致,均确保同一时刻仅一个执行单元进入临界区;但前者面向跨jvm节点场景,依赖redis/zookeeper等外部服务实现互斥、容错与自动续期,后者仅限单jvm内线程间同步,基于内存与cpu指令高效完成。

分布式锁和本地重入锁(如 ReentrantLock 或 synchronized)在解决并发问题的目标上高度一致——都是为了保证**同一时刻只有一个执行单元能进入临界区**,但它们应对的场景、依赖的基础、以及实现逻辑存在本质差异。设计思想上的相通与不同,核心在于“**如何定义‘持有者’、如何判定‘是否已持有’、以及如何安全释放**”。
相通之处:都围绕“可重入 + 互斥 + 状态管理”展开
两者都默认支持可重入性,即同一个执行主体能多次获取同一把锁而不死锁;都通过某种“状态标识”来记录锁归属;也都需要配套的释放机制,避免资源长期被占。
- 线程身份识别是共通前提:本地锁靠线程 ID 判断是否为当前持有者;分布式锁也必须用唯一标识(如 UUID、服务实例 ID + 线程 ID 组合)标记锁归属,否则无法实现可重入和安全释放。
-
计数器逻辑相似:
ReentrantLock内部用 AQS 的state字段记录重入次数;Redis 实现的可重入分布式锁通常用 Hash 结构存 {lockKey: {holderId: "xxx", count: 2}},语义完全对应。 - 释放必须匹配持有者:本地锁要求 unlock 必须由 lock 的同一线程调用;分布式锁同样禁止“张三加锁、李四删除”,否则会引发并发事故,因此解锁必须原子校验 value(如 Lua 脚本比对 requestId)。
不同之处:从“内存可见”走向“跨节点共识”
本地锁运行在单 JVM 内,所有操作基于共享内存和 CPU 指令原子性;分布式锁则必须在不可靠网络中达成多个独立进程间的最小共识,设计重心从“效率”转向“容错”。
- 互斥保障层级不同:本地锁依赖 JVM Monitor 或 AQS,由操作系统/硬件指令(如 CAS)保证原子性;分布式锁依赖外部中间件(Redis/ZK),互斥性建立在“单点写入+原子命令”之上,天然受网络延迟、主从异步、时钟漂移影响。
- 死锁防控策略不同:本地锁崩溃会导致进程终止,JVM 自动清理 Monitor;分布式锁的服务端不感知客户端生死,必须靠超时自动释放(如 Redis 的 PX)、看门狗续期(Redisson)、或临时节点自动销毁(ZooKeeper)来防死锁。
- 一致性模型不同:本地锁是强一致(线性一致性);Redis 单节点锁是最终一致,RedLock 或 ZooKeeper 才提供更强的一致性保障,但代价是性能下降和复杂度上升。
可重入性的实现路径差异明显
本地重入锁的可重入是“自然发生”的——线程 ID 和 state 计数都在 JVM 内存中,读写无延迟、无竞争;而分布式环境下的可重入,需额外设计存储结构和校验逻辑,稍有疏忽就会退化为普通互斥锁甚至出现误删。
- 本地:
nonfairTryAcquire直接比对getExclusiveOwnerThread(),毫秒级完成。 - 分布式:每次加锁都要读取 Redis 中的 holderId 和 count,再决定是新建还是递增;解锁时也要先读再判再删,全程依赖网络 I/O 和脚本原子性,且需处理“读到旧值”等并发边界。
- 典型风险:若业务耗时长,锁过期后被其他客户端抢占,原客户端续期失败却仍继续执行,就会破坏互斥——这在本地锁中根本不存在。
适用边界决定设计取舍
本地重入锁的设计优先考虑低开销、高吞吐、易用性;分布式锁的设计必须把“可用性”和“正确性”放在首位,容忍一定延迟和复杂性。
- 本地锁可以接受短暂自旋(轻量级锁)、快速膨胀(偏向锁→轻量→重量),因为一切发生在本机。
- 分布式锁必须规避单点故障(如 Redis 主从切换丢锁)、网络分区(脑裂)、时钟不同步(影响过期判断),所以引入 RedLock、ZK 顺序节点、Etcd lease 等机制。
- 一个简单事实:你不会给 for 循环加分布式锁,但你会毫不犹豫用
synchronized包裹它——因为粒度和成本决定了设计哲学。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











